码迷,mamicode.com
首页 > 其他好文 > 详细

题解-比赛CF1332

时间:2020-04-02 19:39:17      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:简单   set   特殊情况   最大的   要求   修改   find   let   因此   

题解-比赛CF1332

比赛CF1332

[A] [B] [C] [D] [E] [F] [G]


[A]Exercising Walk

Exercising Walk

\(T\) 组测试数据,每次给定 \(a,b,c,d,x,y,x_1,y_1,x_2,y_2\)。起点是 \((x,y)\),要左走 \(a\) 步,右走 \(b\) 步,下走 \(c\) 步,上走 \(d\) 步(这题的 \(x\)\(y\) 轴与平时相反)。求是否有走法,使得走的过程中总是满足 \(x_1\le x\le x_2\)\(y_1\le y\le y_2\)。如果满足输出 \(\texttt{YES}\),否则输出 \(\texttt{NO}\)

数据范围:\(1\le T\le 10^3\)\(0\le a,b,c,d\le 10^8\)\(a+b+c+d\ge 1\)\(-10^8\le x_1\le x\le x_2\le 10^8\)\(-10^8\le y_1\le y\le y_2\le 10^8\)

本来以为直接找到最终点看看在不在范围内就够了,但是后来发现过不了样例。

有一种特殊情况:\([x_1=x]\&[x=x_2]\&[a,b>0]\&[a+b=0]\)(一走就走出范围了),答案是 \(\texttt{NO}\),你会输出 \(\texttt{YES}\)

对于 \(y,c,d\) 同理,所以特判一下就过了。

易错点:

  1. 没看清这题的 \(x\)\(y\) 轴与平时相反这个特点。
  2. 没考虑到特殊情况(你样例都过不了啊)。

代码:

//Data
int a,b,c,d,x,y,x1,y1,x2,y2;
il int yes(){
	if(a&&b) if(x==x1&&x==x2) return 0;
	if(c&&d) if(y==y1&&y==y2) return 0;
	x-=a,x+=b,y-=c,y+=d;
	return x1<=x&&x<=x2&&y1<=y&&y<=y2;
}

//Main
int main(){
	re int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d%d%d%d%d%d%d",&a,&b,&c,&d,&x,&y,&x1,&y1,&x2,&y2);
		if(yes()) puts("YES"); else puts("NO");
	}
	return 0;
}

[B]Composite Coloring

Composite Coloring

\(T\) 组测试数据,每次给定一个长度为 \(n\) 的合数序列 \(a_i\),需要将每个数染上颜色,使满足对于任意两个颜色相同的数不互质。求一种颜色数为 \(m\) 的染色方案(\(m\) 自选,不需最小,只需满足 \(m\in[1,11]\))。

数据范围:\(1\le T\le 10^3\)\(1\le n\le 10^3\)\(4\le a_i\le 10^3\)\(1\le \sum n\le 10^4\)

对于任意满足数据范围限制的序列绝对有解。

对于任何合数 \(a_i\le 1000\),必然有 \(d\) 满足 \([d|i]\&[d<32]\)

\([1,32)\) 中正好有 \(11\) 个质数,所以遍历每个质数然后把它们的倍数染同色即可。

易错点:

题目中有说对于 \(1\sim m\) 中的每个颜色,必须有该颜色的数,所以需要对颜色离散化。

代码:

//Data
const int N=1000;
int n,a[N+7],co[N+7];

//Prime
bitset<37> np;
vector<int> p;

//Main
int main(){
	for(re int i=2;i<=32;i++){
		if(!np[i]) p.pb(i);
		for(re int j:p)if(i*j>N) break;else np[i*j]=1;
	}
	re int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(re int i=1;i<=n;i++)
			scanf("%d",a+i);
		re int C=0;
		fill(co+1,co+n+1,0);
		for(re int j:p){
			re int ttt=0;
			for(re int i=1;i<=n;i++){
				if(!co[i]&&a[i]%j==0){ttt=1,co[i]=C+1;}
			}
			if(ttt) C++;
		}
		printf("%d\n",C);
		for(re int i=1;i<=n;i++)
			printf("%d%c",co[i],"\n "[i<n]);
	}
	return 0;
}

[C]K-Complete Word

K-Complete Word

\(T\) 组测试数据,给定 \(n\)\(k\) 满足 \(k|n\),给定一个长度为 \(n\) 的字符串 \(s\),求最少修改 \(s\) 的几个字母,使得 \(s\) 是回文串并且对于所有 \(1\le i\le n-k\),满足 \(s_i=s_{i+k}\)

数据范围:\(1\le t\le 10^5\)\(1\le k<n\le 2\times 10^5\)\(\sum n\le 2\times 10^5\)

第二个条件等价于 \(s\)\(\frac nk\)\(k\) 长子段相等;因为 \(s\) 是回文的,所以每个 \(k\) 长子段也是回文的。

所以对于每个 \(1\le i\le \lfloor\frac k2\rfloor\),满足:

\[s_i=s_{k+1-i}=s_{k+i}=s_{k+k+1-i}=\cdots=s_{(\frac nk -1)\cdot k+i}=s_{(\frac nk -1)\cdot k+k+1-i} \]

如果 \(k\in \mathbb{odd}\),对于 \(i=\frac {k+1}2\) 满足:

\[s_i=s_{k+i}=\cdots=s_{(\frac nk -1)\cdot k+i} \]

所以把每群相等的字符中出现次数最多的字符留着,把别的字符改成该字符即可。

代码:

//Data
const int N=200000;
int n,k;
char s[N+7];
int cnt[30];

//Main
int main(){
	re int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d\n%s",&n,&k,s+1);
		re int ans=0;
		for(re int i=1;i<=k/2;i++){
			memset(cnt,0,sizeof cnt);
			re int tmp=0;
			for(re int j=i;j<=n;j+=k) cnt[s[j]-‘a‘]++,tmp++;
			for(re int j=k+1-i;j<=n;j+=k) cnt[s[j]-‘a‘]++,tmp++;
			re int mx=0;
			for(re int i=1;i<26;i++) if(cnt[i]>cnt[mx]) mx=i;
			ans+=tmp-cnt[mx];
		}
		if(k&1){ //k∈odd
			int i=(k+1)/2;
			memset(cnt,0,sizeof cnt);
			re int tmp=0;
			for(re int j=i;j<=n;j+=k) cnt[s[j]-‘a‘]++,tmp++;
			re int mx=0;
			for(re int i=1;i<26;i++) if(cnt[i]>cnt[mx]) mx=i;
			ans+=tmp-cnt[mx];
		}
		printf("%d\n",ans);
	}
	return 0;
}

[D]Walk on Matrix

Walk on Matrix

给定一个 \(k\),要求构造一个随意大小为 \(n\times m\) 的矩阵 \(a_{i,j}\) 使得用
技术图片
得到的答案与从 \((1,1)\)\((n,m)\) 的最小按位与路径答案相差 \(k\)

数据范围:\(1\le n,m\le 500\)\(0\le a_{i,j}\le 3\cdot 10^5\)\(0\le k\le 10^5\)

很巧妙的一题,从数据范围以及样例中可以猜测到这题有通解。

首先这个答案 \(S\) 肯定是比真实答案 \(Ans\) 大的,所以 \(S-Ans=k\)

通过研究第二个样例,可以发现,鲍勃的代码会盲目找最大的,不会考虑如 \(7\&3>8\&3\) 的情况。

所以可以找一个 \(t=2^c>k\),构造如下 \(3\times 4\) 矩阵:

\[\begin{bmatrix} t|k&k&k&0\t&0&k&0\t&t&t|k&k\\end{bmatrix} \]

所以鲍勃的代码 \(dp_{3,3}=t,dp_{3,4}=0\)

而真正的最小按位与路径为 \((t|k)\&k\&k\&k\&(t|k)\&k\),答案为 \(k\)

正好相差 \(k\)

代码:

//Data

//Main
int main(){
	re int k,t=1;
	scanf("%d",&k);
	while(t<=k) t<<=1;
	printf("3 4\n");
	printf("%d %d %d %d\n",t|k,k,k,0);
	printf("%d %d %d %d\n",t,0,k,0);
	printf("%d %d %d %d\n",t,t,t|k,k);
	return 0;
}

[E]Height All the Same

Height All the Same

给定 \(n,m,L,R\),求大小为 \(n\times m\) 的矩阵 \(a_{i,j}\) 中满足 \(L\le a_{i,j}\le R\) 并且可以通过相邻元素一起 \(+1\)、元素 \(+2\) 两种操作使整个矩阵相等的数量 \(\bmod 998244353\)

数据范围:\(1\le n,m,L,R\le 10^9\)\(L\le R\)

很明显 \(L\)\(R\) 的绝对大小不重要,所以设 \(H=R-L+1\)

如果没有后一个限制,答案应该是 \(H^{nm}\)

手玩几下会发现,只要奇偶性满足要求,该矩阵就满足要求,所以:

  1. 如果 \(nm\in\mathbb{odd}\):答案就为 \(H^{nm}\)
  2. 如果 \(nm\in\mathbb{even}\):答案就为 \(\lceil\frac{H^{nm}}{2}\rceil\)

易错点:

  1. \(\bmod 998244353\),除法用逆元,幂 \(\bmod 998244352\)(欧拉定理)。
  2. 快速幂的时候,因为可能 \(H\bmod 998244353=0\),如果 \(nm\bmod 998244352=0\),普通人写的快速幂很容易得到 \(1\),其实应该得到 \(0\)(因此我 \(FST\) 了)。

代码:

//Data
const int Mo=998244353;
int n,m,a,b,h;
lng sz;
il int Pow(re int a,re int x){
	if(a==0) return 0;
	re int res=1;
	for(;x;a=1ll*a*a%Mo,x>>=1)if(x&1)res=1ll*res*a%Mo;
	return res;
}

//Main
int main(){
	scanf("%d%d%d%d",&n,&m,&a,&b);
	h=b-a+1,sz=1ll*n*m;
	if(sz&1) printf("%lld\n",1ll*Pow(h,sz%(Mo-1)));
	else if(h&1) printf("%lld\n",1ll*(Pow(h%Mo,sz%(Mo-1))+1+Mo)%Mo*Pow(2,Mo-2)%Mo);
	else printf("%lld\n",1ll*Pow(h%Mo,sz%(Mo-1))*Pow(2,Mo-2)%Mo);
	return 0;
}

[F]Independent Set

Independent Set

给定树 \(G=(V,E)\)\(n\) 个点。令 \(E‘\in E\),求所有 \(E‘\) 所有边上的节点的独立集数量之和 \(\bmod 998244353\)(独立集大小可以为 \(0\)\(E‘\neq\varnothing\))。

数据范围:\(2\le n\le 3\times10^5\)

这么简单的树形 \(\texttt{dp}\) 我竟然不会,而且想了好久,我太蒻了。

\(f_{o,i}\) 表示:

  1. 如果 \(o=0\)\(i\) 的子树中的答案。
  2. 如果 \(o=1\)\(i\) 不存在或不选时子树中的答案。
  3. 如果 \(o=2\)\(i\) 不存在或选时子树中的答案。

以上“答案”均包括选的边为空的情况。

如果选了该节点,就不能选子节点(独立集的定义),所以:

\[f_{2,i}=\prod_{to\in i‘s~sons}(f_{0,to}+f_{1,to}) \]

如果该节点不选,子节点随意:

\[f_{1,i}=\prod_{to\in i‘s~sons}(f_{0,to}+f_{1,to}+f_{2,to}) \]

容斥原理,减去 \(i\) 不选的情况(即子树任意):

\[f_{0,i}=f_{1,i}+f_{2,i}-\prod_{to\in i‘s~sons}f_{0,to} \]

因为答案不应包括选的边为空的情况,所以最终答案为 \(f_{0,1}-1\)

代码:

//Data
const int N=300000,m=998244353;
int n;
vector<lng> f[3];
vector<vector<int> > e;

//Dfs
il void Dfs(re int x,re int fa){
	f[0][x]=f[1][x]=f[2][x]=1;
	for(re int to:e[x])if(to!=fa){
		Dfs(to,x);
		(f[0][x]*=f[0][to])%=m;
		(f[1][x]*=(f[0][to]+f[1][to]+f[2][to]))%=m;
		(f[2][x]*=(f[0][to]+f[1][to]))%=m;
	}
	f[0][x]=(f[1][x]+f[2][x]-f[0][x]+m)%m;
}

//Main
int main(){
	scanf("%d",&n);
	e.resize(n+7);
	for(re int i=0;i<3;i++) f[i].resize(n+7);
	for(re int i=1,u,v;i<n;i++)
		scanf("%d%d",&u,&v),e[u].pb(v),e[v].pb(u);
	Dfs(1,0);
	printf("%lld\n",(f[0][1]+m-1)%m);
	return 0;
}

未完待续


祝大家学习愉快!

题解-比赛CF1332

标签:简单   set   特殊情况   最大的   要求   修改   find   let   因此   

原文地址:https://www.cnblogs.com/Wendigo/p/12611937.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!