首页 > 其他分享 >2024.8.18 模拟赛 22

2024.8.18 模拟赛 22

时间:2024-09-23 20:13:40浏览次数:1  
标签:fx 22 2024.8 18 s1 ans int fy define

模拟赛

T1 先崩,然后电脑又崩。

题面都在这里了

T1 2-Coloring

原题3100,张口放T1(这是原话)

看起来像 dp,推了两个小时大力分讨,最后式子比我命还长。刚推出来就发现假了

正解差不多人类智慧吧,也可能只是小 trick。

对于整张图,考虑最终染色的“形状”。(下面这个样子)

图片来自 题解 CF1503E 2-Coloring,讲得真的很好。

同一颜色最多会产生两个连通块,如果中间恰好交于一点一共就有四个连通块。

如果我们想对这个图的“形状”进行计数,那么就要找到能够代表图的特征点以便不重不漏,并且应该可以计数。

对于这道题来说,有一个关键就是每一列不能全放、每一行不能不放,在“形状”上表示中间有且只有一列可以将两侧黄色连通块分开

所以我们可以枚举这个临界,然后计算当临界列为 \(i\) 时的方案。

这就将黄色连通块分开了。黄色块会与第 \(i\) 列有两段相交的区间 \((l_1,r_1)\)、\((l_2,r_2)\),我们将 \(r1,l2\) 这对点作为我们计数的标准。

样整个图就变成了四个部分,每个部分都很规整的将两种颜色分成两半。

画图条件有限。

因此我们分别算每个块的方案数就好了!最后把四个块的乘起来。

那么怎么单独求方案数呢?有一种很巧妙的方法就是转化为路径问题。由于要满足选的 \(A,B\) 点是 \(r_1,l_2\) 的位置,所以实际计算时就是算顶点到上面标出的四个点的路径方案数。

这时我们只考虑了黄色被分割的情况,而蓝色被分割其实就是 \(n,m\) 交换一下。

这样先枚举 \(i\),再枚举 \(A,B\) 的复杂度显然是 \(n^3\) 的,如何优化?

假如 \(A\) 点在上方,那么 \(B\) 点其实就是在 \([1,A]\) 的所有情况的和,可以前缀和维护,注意 \(A=B\) 的时候特殊处理。

然后终于做完了。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 4999,mod = 998244353;
int n,m;
LL f[N],inv[N],ans;

void init(int NM)
{
	f[0]=inv[0]=inv[1]=1;
	for(int i=2;i<=NM;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<=NM;i++) f[i]=f[i-1]*i%mod,inv[i]=inv[i-1]*inv[i]%mod;
}
LL way(int x,int y) {return f[x+y]*inv[x]%mod*inv[y]%mod;}
int main()
{
	freopen("magic.in","r",stdin);
	freopen("magic.out","w",stdout);
	scanf("%d%d",&n,&m);
	init(n+m);
	for(int i=1;i<=m-1;i++)
	{
		LL sum=0;
		for(int j=1;j<=n-1;j++)
		{
			sum=(sum+way(i,j-1)*way(i-1,n-j))%mod;
			ans=(ans+sum*way(m-i-1,j)%mod*way(m-i,n-j-1))%mod;
		}
	}
	swap(n,m);
	for(int i=1;i<=m-1;i++)
	{
		LL sum=0;
		for(int j=1;j<=n-1;j++)
		{
			ans=(ans+sum*way(m-i-1,j)%mod*way(m-i,n-j-1))%mod;
			sum=(sum+way(i,j-1)*way(i-1,n-j))%mod;
		}
	}
	printf("%lld\n",(ans<<1ll)%mod);
}

T2 连通块

需要用到树的直径的小性质:

  • 距离树内一点 \(u\) 最远的点一定为树的直径的端点。

  • 两棵树合并后树的直径就是两棵树之前的直径端点间的最大距离(四个点里选两个)。

也就是树的直径可以合并。

对于原题中的删边操作,我们可以转化为逆向的加边操作。这样用并查集维护连通块,并且树的直径可以直接合并。就很简单了。

(第一次有关树据结构的题能自己打出来还一遍过了)

code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int n,m,d[N][2],ans[N];
int head[N],tot;
struct E {int u,v;} e[N<<1],ed[N];
inline void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}

struct Q {int tp,x;} q[N<<1];
bool vs[N];
namespace LCA
{
	int dfn[N],cnt,st[N][21],dep[N],lg[N];
	void dfs(int u,int f)
	{
		dfn[u]=++cnt; st[cnt][0]=f; dep[u]=dep[f]+1;
		for(int i=head[u];i;i=e[i].u) 
		{
			int v=e[i].v; if(v==f) continue;
			dfs(v,u);
		}
	}
	inline int get(int x,int y) {return dfn[x]<dfn[y]?x:y;}
	void init() 
	{
		for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
		for(int i=1;i<=20;i++)
			for(int j=1;j+(1<<i)-1<=n;j++) 
				st[j][i]=get(st[j][i-1],st[j+(1<<i-1)][i-1]);
	}
	int lca(int x,int y) 
	{
		if(x==y) return x;
		if((x=dfn[x])>(y=dfn[y])) swap(x,y);
		int k=__lg(y-x); x++;
		return get(st[x][k],st[y-(1<<k)+1][k]);
	}
	inline int dis(int x,int y) {return dep[x]+dep[y]-(dep[lca(x,y)]<<1);}
}; using namespace LCA;
namespace DSU
{
	int fa[N];
	void init() {for(int i=1;i<=n;i++) fa[i]=i,d[i][0]=d[i][1]=i;}
	int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
	void merge(int x,int y)
	{
		int fx=find(x),fy=find(y);
		int t1=d[fx][0],t2=d[fx][1],tmp=dis(t1,t2),t3;
		for(int i=0;i<=1;i++) for(int j=0;j<=1;j++) 
		{
			t3=dis(d[fx][i],d[fy][j]);
			if(t3>tmp) t1=d[fx][i],t2=d[fy][j],tmp=t3;
		}
		t3=dis(d[fy][1],d[fy][0]); if(t3>tmp) t1=d[fy][0],t2=d[fy][1],tmp=t3;
		fa[fy]=fx; d[fx][0]=t1; d[fx][1]=t2;
	}
	int get(int x)
	{
		int fx=find(x);
		return max(dis(x,d[fx][0]),dis(x,d[fx][1]));
	}
};

int main()
{
	freopen("block.in","r",stdin);
	freopen("block.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		add(x,y); add(y,x); ed[i]={x,y};
	}
	dfs(1,0); init(); DSU::init();
	for(int i=1;i<=m;i++)
	{
		int c,x; scanf("%d%d",&c,&x);
		q[i]={c,x}; if(c==1) vs[x]=1;
	}
	for(int i=1;i<n;i++) if(!vs[i]) DSU::merge(ed[i].u,ed[i].v);
	int cnt=0;
	for(int i=m;i>=1;i--)
	{
		if(q[i].tp==1) DSU::merge(ed[q[i].x].u,ed[q[i].x].v);
		else ans[++cnt]=DSU::get(q[i].x);
	}
	for(int i=cnt;i>=1;i--) printf("%d\n",ans[i]);
	return 0;
}

T3 军队

这其实才是数据结构。。。

题面挺抽象的,但题意奇怪但简单。

我们可以用扫描线处理矩形加,因为只需要维护每一行的信息,所以其实还挺简单的。

重点在于维护什么信息?

我们想要知道每一行中 \(\ge k\) 的个数,并且 \(k \le 30\),首先想到维护 \(\lt k\) 的个数,并从 \(k\) 上操作。

其实小于 \(k\) 的数值只会有 \(k\) 个,我们可以维护前 \(k\) 小的值和数量,\(\lt k\) 的个数一定已经被包含在里面了。

线段树合并时类似归并,挺暴力的。查询只会查整行,所以暴力遍历前 \(k\) 小的值就行了。

每一行记录两种“性别”中较小的那个(因为要配对)。最后回答时贪心,\(lower_bound\) 找一下多少行能取 \(\lfloor \frac{y}{2} \rfloor\)。剩下的顶着取就行了。

这里其实就是 \(\sum a \times (y-a)\),维护一下 \(a\) 和 \(a^2\) 的前缀和(后缀和也可以呢)。(\(a\) 就是那个)。

(一开始用 vector,写法简洁又亲民,\(\mathbb{T}\) 飞了,被迫换数组。)

code
#include<bits/stdc++.h>
#define scan __builtin_scanf
#define print __builtin_printf
using namespace std;
#define fi first
#define se second
#define P pair<int,int>
#define LL long long
const int N = 3e5+5;
int n,m,c,K,Q,s[N];
LL ans,s1[N],s2[N];
struct M {int l,r,v;}; vector<M> v[N];

namespace SEG
{
	struct T {int l,r,lz,cnt=0,kthf[11],kths[11];} tr[N<<2];
	inline void pushup(int k)
	{
		tr[k].cnt=0;
		int sz1=tr[k<<1].cnt,sz2=tr[k<<1|1].cnt;
		int l=1,r=1;
		while(l<=sz1&&r<=sz2&&tr[k].cnt<K)
		{
			if(tr[k<<1].kthf[l]<tr[k<<1|1].kthf[r]) tr[k].kthf[++tr[k].cnt]=tr[k<<1].kthf[l],tr[k].kths[tr[k].cnt]=tr[k<<1].kths[l++];
			else if(tr[k<<1].kthf[l]>tr[k<<1|1].kthf[r]) tr[k].kthf[++tr[k].cnt]=tr[k<<1|1].kthf[r],tr[k].kths[tr[k].cnt]=tr[k<<1|1].kths[r++];
			else tr[k].kthf[++tr[k].cnt]=tr[k<<1].kthf[l],tr[k].kths[tr[k].cnt]=tr[k<<1].kths[l]+tr[k<<1|1].kths[r],l++,r++;
		}
		while(l<=sz1&&tr[k].cnt<K) tr[k].kthf[++tr[k].cnt]=tr[k<<1].kthf[l],tr[k].kths[tr[k].cnt]=tr[k<<1].kths[l++];
		while(r<=sz2&&tr[k].cnt<K) tr[k].kthf[++tr[k].cnt]=tr[k<<1|1].kthf[r],tr[k].kths[tr[k].cnt]=tr[k<<1|1].kths[r++];
	}
	inline void pushdown(int k)
	{
		if(tr[k].lz)
		{
			int lz=tr[k].lz; tr[k].lz=0;
			for(int i=1;i<=tr[k<<1].cnt;i++) tr[k<<1].kthf[i]+=lz;
			for(int i=1;i<=tr[k<<1|1].cnt;i++) tr[k<<1|1].kthf[i]+=lz;
			tr[k<<1].lz+=lz; tr[k<<1|1].lz+=lz;
		}
	}
	inline void bui(int k,int l,int r)
	{
		tr[k].l=l; tr[k].r=r;
		if(l==r) return (tr[k].kthf[++tr[k].cnt]=0,tr[k].kths[tr[k].cnt]=1),void(0);
		int mid=l+r>>1;
		bui(k<<1,l,mid); bui(k<<1|1,mid+1,r);
		pushup(k);
	}
	inline void mdf(int k,int l,int r,int v)
	{
		if(tr[k].l>=l&&tr[k].r<=r) 
		{
			for(int i=1;i<=tr[k].cnt;i++) tr[k].kthf[i]+=v;
			tr[k].lz+=v; return;
		}
		pushdown(k);
		int mid=tr[k].l+tr[k].r>>1;
		if(l<=mid) mdf(k<<1,l,r,v);
		if(r>mid) mdf(k<<1|1,l,r,v);
		pushup(k);
	}
}; using namespace SEG;

int main()
{
	freopen("ar.in","r",stdin);
	freopen("army.out","w",stdout);
	scan("%d%d%d%d%d",&n,&m,&c,&K,&Q);
	for(int i=1;i<=c;i++)
	{
		int x1,x2,y1,y2; scan("%d%d%d%d",&x1,&y1,&x2,&y2);
		v[x1].push_back({y1,y2,1}); v[x2+1].push_back({y1,y2,-1});
	}
	bui(1,1,m);
	for(int i=1;i<=n;i++)
	{
		int res=0;
		for(M j:v[i]) mdf(1,j.l,j.r,j.v);
		for(int i=1;i<=tr[1].cnt;i++)
		{
			if(tr[1].kthf[i]>=K) break;
			res+=tr[1].kths[i];
		}	
		s[i]=min(res,m-res);
	}
	sort(s+1,s+1+n);
	for(int i=n;i>=1;i--) s1[i]=s1[i+1]-s[i]*s[i],s2[i]=s2[i+1]+s[i];
	for(int i=1;i<=Q;i++)
	{
		int x,y; scan("%d%d",&x,&y);
		int p=lower_bound(s+1,s+1+n,y/2)-s;
		if(n-p+1>=x) print("%lld\n",1ll*x*(y/2)*(y-(y/2)));
		else print("%lld\n",1ll*(n-p+1)*(y/2)*(y-(y/2))+s1[n-x+1]-s1[p]+1ll*y*(s2[n-x+1]-s2[p]));
	}
	return 0;
}

T4 棋盘

咕咕咕。。。

标签:fx,22,2024.8,18,s1,ans,int,fy,define
From: https://www.cnblogs.com/ppllxx-9G/p/18366035

相关文章

  • 后台操作出错:索引中丢失 IN 或 OUT 参数:: 22
    简单记录下:今天mybatis中遇到一个错误:org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO law_enforce_user(user_code,name,sex,birthday) VALUES(?,?,?,?)]; SQL state [99999];......
  • 第七届民族品牌全球推介大会定于2024年12月21-22日在京召开
    ......
  • AtCoder Regular Contest 184 D Erase Balls 2D
    转化计数对象。直接数最终剩下的球的集合似乎并不好做。考虑数选择的球的集合(显然选择的顺序不重要,只有选择了哪些球重要)。先把所有球按\(x\)坐标从小到大排序。设我们选择的球的下标为\(i_1<i_2<\cdots<i_k\)。那么能选择这些球当且仅当\(y_{i_1}>y_{i_2}>\cdots......
  • 题解:AT_arc184_a [ARC184A] Appraiser
    题意\(1000\)个硬币中有\(10\)个假币,你每次可以询问两个位置的硬币类型是否相同,你需要用不超过\(950\)次询问找出所有假币的位置。思路将前\(990\)个硬币每\(11\)个分一组,共\(90\)组,余\(10\)个单独分一组。询问每组第\(1\)个硬币和这组后面硬币的关系。因为只......
  • 框架漏洞(5-rce s2-057 CVE-2017-8046 CVE-2018-1273 Shiro-550)
    5-rce步骤一:环境部署cdvulhub/thinkphp/5-rcedocker-composeup-d步骤二:输入系统命令: whoami/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami步骤三:写入webshell到1.php/index.php?s=index/think\ap......
  • 9.18每日总结
    今日学习时间一小时,echarts成功连接到了后天数据库,完成了实时动态表格,但是没并灭有使用ajax的方法,而是通过获取数据,之后进行字符串拼接的方式完成了获取数据库数据<%List<User>userList=(List<User>)session.getAttribute("u");StringBuilderuserIds=newStri......
  • 题解:AT_arc184_a [ARC184A] Appraiser
    本质上还是官方题解的分组并利用\(M\)不大的思路。询问次数\(Q\)离最简单的每个扫一遍就可以知道答案的做法少了\(50\)次。我们考虑如何减少这个次数。首先你可以发现一次询问可以覆盖到两个数,也就是说所有的数都被覆盖时只需要询问\(500\)次。我们考虑把不同的对拉出......
  • 上周热点回顾(9.16-9.22)
    热点随笔:· 从0到1搭建权限管理系统系列二.net8使用JWT鉴权(附当前源码) (陈逸子风)· WiFi基础(四):WiFi工作原理及WiFi接入过程 (liwen01)· 示例项目dotnet/eshop和dotnet/eshopsupport (张善友)· .NET开源工业级移动端仓库管理系统 (小码编匠)· .NET常见的几种......
  • Transact-SQL概述(SQL Server 2022)
    新书速览|SQLServer2022从入门到精通:视频教学超值版_sqlserver2022出版社-CSDN博客《SQLServer2022从入门到精通(视频教学超值版)(数据库技术丛书)》(王英英)【摘要书评试读】-京东图书(jd.com)SQLServer数据库技术_夏天又到了的博客-CSDN博客在前面的章节中,其实已......
  • jetbrains 全家桶激活码(2024年9月22日更新)
    O5JJ0Q0C8Q-eyJsaWNlbnNlSWQiOiJPNUpKMFEwQzhRIiwibGljZW5zZWVOYW1lIjoi5r+A5rS75Zyw5Z2AIGlkZWHCt21lZGVtaW5nwrdjb20iLCJsaWNlbnNlZVR5cGUiOiJQRVJTT05BTCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2Ui......