• Codeforces 1382 / Codeforces Round #658 【部分题解】


    Div. 2 A

    Statement

    \(a,b\) 两数列的最短公共子序列。

    如果存在,输出 YES,第二行输出其长度以及该子序列;如果不存在,输出 NO

    \(|a|,|b| \leq 1000\)

    Solution

    如果存在,显然长度为 \(1\)。枚举即可。

    Code

    # include <bits/stdc++.h>
    # define rr
    const int N=1010,INF=0x3f3f3f3f;
    int tota[N],totb[N];
    int n,m;
    int a[N],b[N];
    int T;
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    int main(void){
    	T=read();
    	while(T--){
    		memset(tota,0,sizeof(tota)),memset(totb,0,sizeof(totb));
    		n=read(),m=read();
    		for(rr int i=1;i<=n;++i){
    			a[i]=read(),++tota[a[i]];
    		}
    		for(rr int i=1;i<=m;++i){
    			b[i]=read(),++totb[b[i]];
    		}
    		int ans=-1;
    		for(rr int i=1;i<=1000;++i){
    			if(tota[i]&&totb[i]){
    				ans=i;
    				break;
    			}
    		}
    		if(~ans){
    			printf("YES\n1 %d\n",ans);
    		}else{
    			printf("NO\n");
    		}
    	}
    
    	return 0;
    }
    

    Div.2 B

    Statement

    给定 \(n\) 堆石子,第 \(i\) 堆有 \(a_i\) 个。先后手轮流取,每次取编号最小非空堆,至少取一个。问最优操作下谁必胜。

    \(n \leq 100000,a_i \leq 10^9\)

    Solution

    \(a_1>1\) 的时候,如果拿完第一堆必胜,那么先手会这么做;如果拿完第一堆必败,那么先手会留下一个,迫使后手拿完第一堆。综上,当 \(a_1 >1\) 时,先手必胜。

    但如果前缀中有奇数个 \(1\),那么胜负就会反转:后手会操作第一个 \(>1\) 的堆,按照上面的策略让自己胜利。

    这样有一个特殊情况:所有的堆都只有一个石子。这样判断 \(n\) 的奇偶性即可。

    Code

    # include <bits/stdc++.h>
    # define rr
    const int N=100010,INF=0x3f3f3f3f;
    int n;
    int a[N];
    
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    int main(void){
    	int T=read();
    	while(T--){
    		n=read();
    		bool flag=true;
    		int tot=0;
    		for(rr int i=1;i<=n;++i){
    			a[i]=read();
    			flag&=(a[i]==1);
    			if(flag){
    				++tot;
    			}
    		}
    		if(flag){
    			puts((n%2)?"First":"Second");
    		}else{
    			puts((tot%2)?"Second":"First");
    		}
    
    	}
    
    	return 0;
    }
    

    Div. 1 A (Hard Version)

    Statement

    给定长为 \(n\)\(01\)\(a,b\)。每次可以选择 \(a\) 的一个前缀,将其取反(\(1\)\(0\)\(0\)\(1\)),然后该前缀翻转。

    例如,\(a=001011\),选择前缀为 \(3\) 的前缀操作,\(a\) 变为 \(011011\)。然后选择整个字符串操作,\(a\) 变成 \(001001\)

    使用不超过 \(2n\) 次操作将 \(a\) 变成 \(b\)

    Solution

    \(n\) 次操作,考虑将 \(a\) 变成全 \(0/1\)。具体来讲,如果 \(a\) 具有相同颜色的最长前缀颜色长度为 \(i(i<n)\),那么可以使用操作将该前缀的颜色取反,得到一个长度至少为 \(i+1\) 的具有相同颜色的最长前缀。

    例如,\(a=01101\)

    • 将长度为 \(1\) 的前缀颜色取反,\(a=11101\)
    • 将长度为 \(3\) 的前缀颜色取反,\(a=00001\)
    • 将长度为 \(4\) 的前缀颜色取反,\(a=11111\)

    因为每取反一次,具有相同颜色的最长前缀的长度就增加 \(1\),所以至多 \(n\) 次就可以将 \(a\) 变成全 \(0/1\)

    \(n\) 次操作,将 \(a\) 变成 \(b\)。例如,\(a=111111,b=011010\)。我们从后往前操作 \(b\) 中每一个具有相同颜色的连续段。

    • \(b_6=0\),于是我们将 \(a\) 全部取反,\(a=000000\)
    • \(b_5=1\),将长度为 \(5\) 的前缀颜色取反,\(a=111110\)
    • \(b_4=0\),将长度为 \(4\) 的前缀颜色取反,\(a=000010\)
    • \(b_{2,3}=1\),将长度为 \(3\) 的前缀颜色取反,\(a=111010\).
    • \(b_1=0\),将长度为 \(1\) 的前缀颜色取反,\(a=011010\)

    可以想象在一个颜色板上不断地涂上新颜色的操作。

    由于 \(b\) 中至多有 \(n\) 个不同的颜色段,所以至多 \(n\) 次就可以将 \(a\) 变成 \(b\)

    # include <bits/stdc++.h>
    # define rr
    const int N=200010,INF=0x3f3f3f3f;
    char a[N],b[N];
    int ans[N],cnt;
    int n;
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    int main(void){
    	int T=read();
    	while(T--){
    		n=read();
    		scanf("%s",a+1);
    		scanf("%s",b+1);
    		char now=a[1];
    		int cnt=0;
    		for(rr int i=2;i<=n;++i){
    			if(a[i]!=now){
    				ans[++cnt]=i-1,now=a[i];
    			}
    		}
    		char suv=b[n];
    		int st=n;
    		for(rr int i=n-1;i;--i){
    			if(suv!=b[i]){
    				if(now!=suv){
    					ans[++cnt]=st;
    					now=suv;
    				}
    				suv=b[i];
    				st=i;
    			}
    		}
    		if(b[1]!=now){
    			ans[++cnt]=st;
    		}
    		printf("%d ",cnt);
    		for(rr int i=1;i<=cnt;++i){
    			printf("%d ",ans[i]);
    		}
    		puts("");
    	}
    	return 0;
    }
    

    Div.1 B

    Statement

    对于两个数组 \(a,b\),定义 \(\text{merge}(a,b)\)

    \[ \text{merge}(a,b)=\left\{ \begin{aligned} \empty & & a=b=\empty \\ a & & b=\empty \\ b & & a=\empty \\ a_1+\text{merge}([a_2,...a_n],b) & & a_1<b_1 \\ b_1+\text{merge}(a,[b_2,...b_m]) & & a_1>b_1 \end{aligned} \right. \]

    给定长为 \(2n\) 的排列 \(p\),问是否存在长为 \(n\)\(a,b\) 使得 \(\text{merge}(a,b)=p\)

    \(n \leq 2000\)

    Solution

    \(p\) 分段。设 \(p_{2n+1}=\infty\),将 \(p_1,p_2,...,p_k(p_1=\max\{p_1,p_2,...,p_k\},p_{k+1}>p_1)\) 分在一起,然后从 \(p\) 中去除它们。

    容易发现,每一段的数必须分在一个数组中。如果不这么做,一定会导致 \(\text{merge}(a,b)\) 的结果中,每一段中第一个数出现的位置比后面的数晚,因为第一个数是这一段的最大值。

    求出每一段的长度,然后可以使用简单的动态规划来判断是否有若干段的长度和正好为 \(n\)。如果存在,那么就有至少一组合法解。

    Code

    # include <bits/stdc++.h>
    # define rr
    const int N=5010,INF=0x3f3f3f3f;
    int T;
    int val[N],dp[N];
    int n;
    int g[N],m;
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    int main(void){
    	T=read();
    	while(T--){
    		n=read();
    		for(rr int i=1;i<=2*n;++i){
    			val[i]=read();
    		}
    		m=0;
    		g[++m]=1;
    		int now=val[1];
    		for(rr int i=2;i<=2*n;++i){
    			if(now>val[i]){
    				++g[m];
    			}else{
    				now=val[i],g[++m]=1;
    			}
    		}
    		memset(dp,0,sizeof(dp)),dp[0]=1;
    		for(rr int i=1;i<=m;++i){
    			for(rr int j=n;j>=g[i];--j){
    				dp[j]|=dp[j-g[i]];
    			}
    		}
    		puts(dp[n]?"YES":"NO");
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    走线规范-标识
    python学习之网路操作
    python学习之函数
    RTT学习之软件包
    RT_THREAD之组件学习
    RT_THREAD之nano学习
    物联网相关的模块
    JavaScript学习笔记之二
    javascript完美实现图片拖动改变顺序
    响应式WEB设计的9项基本原则
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/13360744.html
Copyright © 2020-2023  润新知