ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ZJOI2022 题解

2022-05-10 21:01:54  阅读:317  来源: 互联网

标签:le int 题解 sum sqrt times ZJOI2022 mod


ZJOI2022 部分题目题解

D1T1 [ZJOI2022] 树

题意

按照如下方式生成两棵树:

  • 第一棵树:节点 \(1\) 作为树的根,\(\forall i\in[2,n]\),从 \([1,i-1]\) 中选取一个点作为 \(i\) 的父亲。
  • 第二棵树:节点 \(n\) 作为树的根,\(\forall i\in[1,n-1]\),从 \([i+1,n]\) 中选取一个点作为 \(i\) 的父亲。

要求对于所有节点 \(i​\),\(i​\) 恰好是两棵树中的一个的叶子节点。一个节点被称为叶子当且仅当没有节点的父亲是它。两种方案不同当且仅当存在一棵树中的一个节点 \(i​\),两种方案中它的父亲不同。

对于 \(n\in[2,N]\),计算方案数 \(\bmod m\)。

数据范围:\(n\le 500\)。

solution

设 \(f(S)\) 表示第一棵树中,叶子集合恰好为 \(S\) 的方案数,\(g(S)\) 表示第二棵树中,叶子集合恰好为 \(S\) 的方案数。为了方便容斥,设 \(f'(S)\) 表示第一棵树中,叶子集合为 \(S\) 的超集的方案数,\(g'(S)\) 表示第二棵树中,叶子集合为 \(S\) 的超集的方案数。

那么

\[f(S)=\sum_{S\subseteq s}(-1)^{|s|-|S|}f'(s)\\ g(S)=\sum_{S\subseteq s}(-1)^{|s|-|S|}g'(s)\\ \]

答案是(设 \(U\) 为全集 \(1\sim n\))

\[\begin{aligned} ans&=\sum_S f(S)g(U\setminus S)\\ &=\sum_S\left(\sum_{S\subseteq s}(-1)^{|s|-|S|}f'(s)\right)\left(\sum_{U\setminus S\subseteq t}(-1)^{|U\setminus S|-|t|}g'(t)\right)\\ &=\sum_S\left(\sum_{S\subseteq s}(-1)^{|s|-|S|}f'(s)\right)\left(\sum_{t\in S}(-1)^{|S|-|t|}g'(U\setminus t)\right)\\ &=\sum_{s}f'(s)\sum_{t\subseteq s}g’(U\setminus t)\sum_{t\subseteq S\subseteq s}(-1)^{|S|-|s|}(-1)^{|S|-|t|}\\ &=\sum_{s}f'(s)\sum_{t\subseteq s}g'(U\setminus t)(-2)^{|s|-|t|} \end{aligned} \]

最后一步转化是 \((-1)^{|S|-|s|}(-1)^{|S|-|t|}=(-1)^{|s|-|t|}\),合法的 \(S\) 共 \(2^{|s|-|t|}\) 个。

考虑 DP 维护转移系数。\(i\) 对 \(f'(s)\) 的贡献是 \(j\in[1,i-1],j\not \in s\) 的 \(j\) 的数量,\(i\) 对 \(g'(U\setminus s)\) 的贡献是 \(j\in[i+1,n],j\in s\) 的 \(j\) 的数量。那么设 DP 状态 \(f_{i,x,y}\) 表示考虑完前 \(i\) 个点,已经放在 \(s\) 中的点的数量为 \(x\),钦定后面有 \(y\) 个点在 \(t\) 集合内的 \(\sum_{s}f'(s)\sum_{t\subseteq s}g'(U\setminus t)(-2)^{|s|-|t|}\)。

转移有:

\[f_{i,x,y}\gets f_{i-1,x,y}\times x\times y\\ f_{i,x+1,y-1}\gets f_{i-1,x,y}\times x\times (y-1)\\ f_{i,x+1,y}\gets -2\times f_{i-1,x,y}\times x\times y \]

分别表示 不属于 \(s\)、属于 \(s\) 也属于 \(t\),只属于 \(s\) 不属于 \(t\)。空间可以滚动一下。

复杂度 \(O(n^3)\)。

view code
#include <bits/stdc++.h>
using namespace std;
const int N=505;
int mod;
int f[2][N][N],n;
int main(){
	cin>>n>>mod;
	int pre=0,cur=1;
	for(int i=1;i<=n;++i)f[0][0][i]=1;
	for(int i=1;i<=n;pre^=1,cur^=1,++i){
		memset(f[cur],0,sizeof(f[cur]));
		int ans=0;
		for(int j=0;j<i;++j){
			for(int k=0;k<=n-i+1;++k){
				int l=(i==1)?1:i-1-j;
				f[cur][j][k]=(f[cur][j][k]+1ll*f[pre][j][k]*l*k)%mod;
				if(k==1)ans=(ans+1ll*f[pre][j][k]*l)%mod;
				if(i>1){
					if(k)f[cur][j+1][k-1]=(f[cur][j+1][k-1]+1ll*f[pre][j][k]*l*(k-1))%mod;
					f[cur][j+1][k]=(f[cur][j+1][k]-2ll*f[pre][j][k]*l*k)%mod;
				}
			}
		}
		if(i>1)printf("%d\n",(ans+mod)%mod);
	}
	return 0;
}

D1T2 [ZJOI2022] 众数

题意

给你序列 \(a_1,a_2,\cdots a_n\)。你可以进行一次操作,选择一个区间 \([l,r](1\le l\le r\le n)\) 和一个整数 \(k\),将区间 \([l,r]\) 的数 \(+k\)。询问操作之后众数的出现次数的最大值,并输出这个众数的所有可能取值。

数据范围:\(T\) 组数据,\(T\le 20,2\le n\le 2\times 10^5,\sum n\le 5\times 10^5,1\le a_i\le 10^9,\) 所有 \(a_i\) 不全相等。

solution

我们最终的答案一定是选择一个有序对 \((x,y)\),然后选择一个区间,把这个区间内的 \(y\) 全变成 \(x\)(此时这个区间内的 \(x\) 会变成一个 \(\neq x\) 的数),让众数变成 \(x\)。

考虑根号分治。

  • 若 \((x,y)\) 中 \(x\) 的出现次数 \(\ge \sqrt{n}\) 或 \(y\) 的出现次数 \(\ge \sqrt n\)

枚举所有出现次数 \(\ge \sqrt{n}\) 的 \(i\)。现在我们要对所有 \(j\) 求出以下两个东西:

  1. 原序列中,\(i\) 的权值为 \(1\),\(j\) 的权值为 \(-1\),其它位置权值为 \(0\) 的最大子段和(此时众数为 \(j\))。
  2. 原序列中,\(i\) 的权值为 \(-1\),\(j\) 的权值为 \(1\),其它位置权值为 \(0\) 的最大子段和(此时众数为 \(i\))。

这两个东西都可以 \(O(n)\) 扫一遍,维护每个不同的 \(j\) 的前缀和的最小值求出。

因为出现次数 \(\ge \sqrt{n}\) 的数的数量 \(\le \sqrt{n}\),这一部分的复杂度是 \(O(n\sqrt{n})\)。

  • \((x,y)\) 中 \(x,y\) 的出现次数均 \(\le \sqrt{n}\)

我们要求的还是:原序列中,\(i\) 的权值为 \(-1\),\(j\) 的权值为 \(1\),其它位置权值为 \(0\) 的最大子段和(此时众数为 \(j\))。

因为 \(i\) 的出现次数 \(\le \sqrt{n}\),我们找出 \(i\) 的所有区间(这样我们知道里面有多少个 \(-1\),这样的区间最多 \(O(n\sqrt{n})\) 个),现在的问题是 \(O(n\sqrt{n})\) 个区间的区间众数。

直接求区间众数没法快速求出,注意到这个区间众数一定 \(\le \sqrt{n}\)(因为 \(y\) 的出现次数 \(\le\sqrt{n}\)),我们暴力枚举这个区间众数是多少,设为 \(p\),那么我们对每个右端点 \(r\),双指针找到一个最靠右的左端点 \(l\),满足 \([l,r]\) 的区间众数为 \(p\)。我们就能回答所有右端点为 \(r\),左端点 \(\le l\) 的所有询问了。

这一部分的复杂度也是 \(O(n\sqrt{n})\)。

总复杂度 \(O(n\sqrt{n})\)。

view code
#include <bits/stdc++.h>
using namespace std;
inline int read(){
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
	return s*f;
}
const int N=2e5+5;
int a[N],b[N],n,B,T,mx[N],s[N],tcnt[N],tot;
vector<int> ans;
template<typename T>inline void Max(T&a,T b){if(a<b)a=b;}
template<typename T>inline void Min(T&a,T b){if(a>b)a=b;}
namespace sub1{
	int buc[N],t,s[N],mn[N],mn1[N];
	bool tag[N];
	inline void work(int c){
		t=0;
		for(int i=1;i<=tot;++i)tag[i]=1,mn[i]=0,mn1[i]=0,s[i]=0,buc[i]=i;
		t=tot;
		int cnt=0;
		for(int i=1;i<=n;++i){
			if(a[i]==c){
				for(int j=1;j<=t;++j)tag[buc[j]]=0;
				++cnt;t=0;
			}else{
				const int col=a[i];
				++s[col];
				if(!tag[col]){
					Min(mn[col],s[col]-1-cnt);
					tag[col]=1;
					buc[++t]=col;
				}
				Max(mx[col],cnt-s[col]+1-mn1[col]+tcnt[col]);
				Max(mx[c],s[col]-cnt-mn[col]+tcnt[c]);
				Min(mn[col],s[col]-cnt);
				Min(mn1[col],cnt-s[col]);
			}
		}
		for(int i=1;i<=tot;++i)if(i!=c)Max(mx[i],cnt-s[i]-mn1[i]+tcnt[i]);
	}
}
int curmx;
namespace sub2{
	vector<int> buc[N];
	int cnt[N],ccnt[N],app;
	inline void insert(int x){
		--ccnt[cnt[x]];
		++ccnt[++cnt[x]];
		Max(app,cnt[x]);
	}
	inline void del(int x){
		--ccnt[cnt[x]];
		++ccnt[--cnt[x]];
		if(!ccnt[app])--app;
	}
	int L[N],rk[N],L1[N];
	inline void work(){
		for(int i=B;i>=1&&i+B>=curmx;--i){
			int r=0,l=1;
			app=0;
			memset(cnt+1,0,tot<<2);
			memset(ccnt+1,0,n<<2);
			ccnt[0]=tot;
			while(r<=n&&app<i)
				insert(a[++r]);
			if(app<i)continue;
			del(a[r]);
			for(;r<=n;++r){
				insert(a[r]);
				while(app>=i)del(a[l++]);
				insert(a[--l]);
				if(r==n){
					for(int c=1;c<=tot;++c){
						if(tcnt[c]>=B)continue;
						while(L1[c]<=tcnt[c]&&buc[c][L1[c]]<=l){
							Max(mx[c],app-(tcnt[c]-L1[c])+tcnt[c]);
							Max(curmx,mx[c]);
							++L1[c];
						}
					}
					break;
				}
				int c=a[r+1];
				if(tcnt[c]>=B)continue;
				while(L[r+1]<rk[r+1]&&buc[c][L[r+1]]<=l){
					Max(mx[c],app-(rk[r+1]-L[r+1]-1)+tcnt[c]);
					Max(curmx,mx[c]);
					++L[r+1];
				}
			}
		}
	}
	inline void init(){
		for(int i=1;i<=tot;++i){
			buc[i].clear();
			buc[i].push_back(0);
			L1[i]=0;
		}
		for(int i=1;i<=n;++i)L[i]=0,buc[a[i]].push_back(i),rk[i]=buc[a[i]].size()-1;
	}
}
int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i)a[i]=read(),b[i]=a[i];
		tot=n;curmx=0;
		sort(b+1,b+1+tot);
		tot=unique(b+1,b+1+tot)-b-1;
		for(int i=1;i<=n;++i)
			a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
		for(int i=1;i<=tot;++i)mx[i]=0,tcnt[i]=0;
		for(int i=1;i<=n;++i)++tcnt[a[i]];
		B=sqrt(n);
		for(int i=1;i<=tot;++i)if(tcnt[i]>=B)sub1::work(i);
		for(int i=1;i<=tot;++i)Max(curmx,mx[i]);
		sub2::init();
		sub2::work();
		int maxx=0;
		for(int i=1;i<=tot;++i)Max(maxx,mx[i]);
		printf("%d\n",maxx);
		for(int i=1;i<=tot;++i)
			if(mx[i]==maxx)printf("%d\n",b[i]);
	}
	return 0;
}

D2T2 [ZJOI2022] 计算几何

题意

(写不动简要题意了)

九条可怜是一个喜欢计算几何的女孩子,她画了一个特别的平面坐标系,其中 xx 轴正半轴与 yy 轴正半轴夹角为 \(60\) 度。

从中,她取出所有横纵坐标不全为偶数,且满足 \(-2 a + 1 \le x \le 2 a - 1\),\(-2 b + 1 \le y \le 2 b - 1\),\(-2 c + 1 \le x + y \le 2 c - 1\) 的整点。

可怜想将其中一些点染色,但相邻的点不能同时染色。具体地,对于点 \((x,y)\),它和 \((x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y), (x + 1, y - 1), (x - 1, y + 1)\) 六个点相邻,可结合样例解释理解。

可怜想知道在这个规则下最多能将多少点染色,以及染最多点的染色方案数。由于后者值可能很大,对于染色方案数,你只需要输出对 998244353 取模后的结果。注意不需要将最多染色点数取模。

(其中 A,Q,H 三点是被删除的,不能被选择)

数据范围:\(1\le a,b,c\le 10^6\),\(T\) 组数据,\(1\le T\le 10\)

solution

把所有横纵坐标都是偶数的点连出变成为 \(2\) 的等边三角形,容易发现,所有没被删除的点都是一个等边三角形某一边的中点。把两个有公共边的等边三角形连边,这条边就表示这个边上的中点选不选

原问题中,两个点不能相邻的条件相当于新的图上,两条被选择的边不能有公共点。即一个最大匹配计数。

容易发现,这个题转化之后与 [Cnoi2021]六边形战士。其中原文题的 \(A=\max(0,a+b-c),B=\max(0,a+c-b),C=\max(0,b+c-a)\)。ZJOI 这题还需要求最大匹配的大小,这个最大匹配是完美匹配,所以最大匹配是 \(A\times B+B\times C+A\times C\)。

view code
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5,mod=998244353;
int T;
inline int Inv(int a){
	int ret=1,b=mod-2;
	for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ret=1ll*ret*a%mod;
	return ret;
}
int fac[N],h[N];
inline int calc(int a,int b,int c){
	int n=a+b+c;
	return 1ll*h[a]*h[b]%mod*h[c]%mod*h[n]%mod*Inv(1ll*h[a+b]*h[b+c]%mod*h[a+c]%mod)%mod;
}
int a[100],b[100],c[100],mx;
inline void init(int n){
	fac[0]=1;h[0]=1;
	for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%mod,h[i]=1ll*h[i-1]*fac[i-1]%mod;
}
int main(){
	cin>>T;
	for(int i=1;i<=T;++i){
		cin>>a[i]>>b[i]>>c[i];
		mx=max(mx,a[i]+b[i]+c[i]);
	}
	init(mx);
	for(int i=1;i<=T;++i){
		a[i]=min(a[i],b[i]+c[i]);
		b[i]=min(b[i],a[i]+c[i]);
		c[i]=min(c[i],a[i]+b[i]);
		int a1=a[i]+b[i]-c[i],b1=a[i]+c[i]-b[i],c1=b[i]+c[i]-a[i];
		printf("%lld %d\n",1ll*a1*b1+1ll*b1*c1+1ll*a1*c1,calc(a1,b1,c1));
	}
	return 0;
}

标签:le,int,题解,sum,sqrt,times,ZJOI2022,mod
来源: https://www.cnblogs.com/harryzhr/p/16255302.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有