题解(658.div2)

题解(658.div2)

A:Common Subsequence

You are given two arrays of integers a1,…,an and b1,…,bm.
Your task is to find a non-empty array c1,…,ck that is a subsequence of a1,…,an and also a subsequence of b1,…,bm If there are multiple answers, find one of the smallest possible length. If there are still multiple of the smallest possible length, find any. If there are no such arrays, you should report about it.
A sequence a is a subsequence of a sequence b if a can be obtained from b by deletion of several (possibly, zero) elements. For example, [3,1] is a subsequence of [3,2,1] and [4,3,1], but not a subsequence of [1,3,3,7] and [3,10,4].
Input
The first line contains a single integer tt (1≤t≤1000) — the number of test cases. Next 3t lines contain descriptions of test cases.
The first line of each test case contains two integers n and m (1≤n,m≤1000) — the lengths of the two arrays.
The second line of each test case contains nn integers a1,…,an (1≤ai≤1000) — the elements of the first array.
The third line of each test case contains mm integers b1,…,bm (1≤bi≤1000) — the elements of the second array.
It is guaranteed that the sum of nn and the sum of mm across all test cases does not exceed 1000(∑i=1tni,∑i=1tmi≤1000).
Output
For each test case, output “YES” if a solution exists, or “NO” otherwise.
If the answer is “YES”, on the next line output an integer kk (1≤k≤1000) — the length of the array, followed by k integers c1,…,ck (1≤ci≤1000) — the elements of the array.
If there are multiple solutions with the smallest possible kk, output any.

这道题是一道数学题,同样是总结算法。

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
bool isp(int x){
	if(x<2)return 0;
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0) return 0;
	}
	return 1;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
int num[1005],t=read();
int main(){
	while(t--){
		memset(num,0,sizeof(num));
		int n=read(),m=read();
		for(int i=1;i<=n;i++){
			int a=read();
			num[a]=1;
		}
		for(int i=1;i<=m;i++){
			int b=read();
			if(num[b]==1)num[b]=2;
		}
		bool flag=0;
		for(int i=1;i<=1000;i++)
			if(num[i]==2){
				cout<<"YES"<<endl<<1<<" "<<i<<endl;
				flag=1;
				break;
			}
		if(!flag)cout<<"NO"<<endl;
	}
	return 0;
}

B:Sequential Nim

There are n piles of stones, where the i-th pile has ai stones. Two people play a game, where they take alternating turns removing stones.
In a move, a player may remove a positive number of stones from the first non-empty pile (the pile with the minimal index, that has at least one stone). The first player who cannot make a move (because all piles are empty) loses the game. If both players play optimally, determine the winner of the game.
Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2*t lines contain descriptions of test cases.
The first line of each test case contains a single integer n (1≤n≤105) — the number of piles.
The second line of each test case contains nn integers a1,…,an (1≤ai≤109) — aiai is equal to the number of stones in the i-th pile.
It is guaranteed that the sum of n for all test cases does not exceed 105.
Output
For each test case, if the player who makes the first move will win, output “First”. Otherwise, output “Second”.

这道题看上去是一道模板题,但是实际上它需要混合尼姆博弈和自创算法。

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
bool isp(int x){
	if(x<2)return 0;
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0) return 0;
	}
	return 1;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
int a[200000];
int main(){
	int t=read();
	while(t--){
		int n=read(),ans=0,pd=1;
		bool is=0;
		for(int i=1;i<=n;i++){
			a[i]=read();
			if(a[i]==1&&!is){
				pd++;
				pd%=2;
			}else{
			    is=1;	
			}
		}
		if(!is){
			if(n%2==0){
				printf("Second\n");
			}
			else{
				printf("First\n");
			}
		}else{
			if(!pd){
			    printf("Second\n");
		    }
		    else{
			    printf("First\n");
		    }
		}
	}
    return 0;
}

C:Prefix Flip

There are two binary strings a and b of length n (a binary string is a string consisting of symbols 0 and 1). In an operation, you select a prefix of a, and simultaneously invert the bits in the prefix (0 changes to 1 and 1 changes to 0) and reverse the order of the bits in the prefix.
For example, if a=001011 and you select the prefix of length 3, it becomes 011011. Then if you select the entire string, it becomes 001001.
Your task is to transform the string aa into bb in at most 2n operations. It can be proved that it is always possible.
Input
The first line contains a single integer tt (1≤t≤1000) — the number of test cases. Next 3t lines contain descriptions of test cases.
The first line of each test case contains a single integer nn (1≤n≤105) — the length of the binary strings.
The next two lines contain two binary strings aa and bb of length n.
It is guaranteed that the sum of n across all test cases does not exceed 105.
Output
For each test case, output an integer k (0≤k≤2n), followed by kk integers p1,…,pk(1≤pi≤n). Here k is the number of operations you use and pi is the length of the prefix you flip in the i-th operation.

这道题也需要考生自行设计数学算法。

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
bool isp(int x){
	if(x<2)return 0;
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0) return 0;
	}
	return 1;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
int a[200000],b[200000];
int main(){
	int t;
	cin>>t;
	while(t--){
		int cnt=0,cnt1=0;
		string a1,b1;
		int n=read();
		cin>>a1>>b1;
		for(int i=1;i<n;i++)
			if(a1[i]!=a1[i-1])
				a[cnt++]=i;
		for(int i=1;i<n;i++)
			if(b1[i]!=b1[i-1])b[cnt1++]=i;
		if(b1[n-1]!=a1[n-1])a[cnt++]=n;
		cout<<cnt+cnt1<<" ";
		for(int i=0;i<cnt;i++)cout<<a[i]<<" ";
		for(int i=cnt1-1;i>=0;i--)cout<<b[i]<<" ";
		cout<<endl;
	}
	return 0;
}

D:Unmerge

Let a and b be two arrays of lengths n and m, respectively, with no elements in common. We can define a new array merge(a,b) of length n+m recursively as follows:
If one of the arrays is empty, the result is the other array. That is, merge(∅,b)=b and merge(a,∅)=a. In particular, merge(∅,∅)=∅.
If both arrays are non-empty, and a1<b1, then merge(a,b)=[a1]+merge([a2,…,an],b). That is, we delete the first element a1 of a, merge the remaining arrays, then add a1 to the beginning of the result.
If both arrays are non-empty, and a1>b1, then merge(a,b)=[b1]+merge(a,[b2,…,bm]). That is, we delete the first element b1 of b, merge the remaining arrays, then add b1 to the beginning of the result.
This algorithm has the nice property that if a and b are sorted, then merge(a,b) will also be sorted. For example, it is used as a subroutine in merge-sort. For this problem, however, we will consider the same procedure acting on non-sorted arrays as well. For example, if a=[3,1] and b=[2,4], then merge(a,b)=[2,3,1,4].
A permutation is an array consisting of n distinct integers from 1 to n in arbitrary order. For example, [2,3,1,5,4] is a permutation, but [1,2,2]is not a permutation (2 appears twice in the array) and [1,3,4] is also not a permutation (n=3 but there is 4 in the array).
There is a permutation p of length 2n. Determine if there exist two arrays a and b, each of length n and with no elements in common, so that p=merge(a,b).
Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2t lines contain descriptions of test cases.
The first line of each test case contains a single integer n (1≤n≤2000).
The second line of each test case contains 2n integers p1,…,p2n (1≤pi≤2n). It is guaranteed that p is a permutation.
It is guaranteed that the sum of n across all test cases does not exceed 2000.
Output
For each test case, output “YES” if there exist arrays a, b, each of length n and with no common elements, so that p=merge(a,b). Otherwise, output “NO”.

这道题需要同时结合数学算法和动态规划,有难度。

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
bool isp(int x){
	if(x<2)return 0;
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0) return 0;
	}
	return 1;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
int dp[5000][5000][2]={},T=read();
int main(){
	while(T--){
		int a[5000]={},sta[5000]={},vsm[5000]={},dsm[5000]={},n=read();
		for(int i=1;i<=2*n;i++){
			a[i]=read();
			for(int j=0;j<=n;j++)dp[i][j][0]=dp[i][j][1]=0;
		}
		for(int i=2*n,tp=0;i;i--){
			if(i>n)dp[i][2*n+1-i][0]=dp[i][0][1]=1;
			while(tp&&a[sta[tp]]<a[i]){
				for(int j=0;j<=n;j++)vsm[j]-=dp[sta[tp]][j][0];
				for(int j=sta[tp];j<=2*n&&j-sta[tp]<=n;j++)dsm[j]-=dp[sta[tp]][j-sta[tp]][1];
				tp--;
			}
			for(int j=max(n+1-i,0);j<=n&&j+i<=2*n+1;j++){
				dp[i][j][1]=vsm[j];
				if(j+i<=2*n)dp[i][j][0]=dsm[j+i];
			}
			sta[++tp]=i;
			for(int j=0;j<=n;j++)vsm[j]+=dp[i][j][0];
			for(int j=i;j<=2*n&&j-i<=n;j++)dsm[j]+=dp[i][j-i][1];
		}
		if(dp[1][n][0]|dp[1][n][1])cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

E:Mastermind

In the game of Mastermind, there are two players — Alice and Bob. Alice has a secret code, which Bob tries to guess. Here, a code is defined as a sequence of nn colors. There are exactly n+1 colors in the entire universe, numbered from 1 to n+1 inclusive.
When Bob guesses a code, Alice tells him some information about how good of a guess it is, in the form of two integers x and y.
The first integer x is the number of indices where Bob’s guess correctly matches Alice’s code. The second integer y is the size of the intersection of the two codes as multisets. That is, if Bob were to change the order of the colors in his guess, yy is the maximum number of indices he could get correct.
For example, suppose n=5, Alice’s code is [3,1,6,1,2], and Bob’s guess is [3,1,1,2,5]. At indices 1 and 2 colors are equal, while in the other indices they are not equal. So x=2. And the two codes have the four colors 1,1,2,3 in common, so y=4.
Solid lines denote a matched color for the same index. Dashed lines denote a matched color at a different index. x is the number of solid lines, and y is the total number of lines.
You are given Bob’s guess and two values x and y. Can you find one possibility of Alice’s code so that the values of x and y are correct?
Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2t lines contain descriptions of test cases.
The first line of each test case contains three integers n,x,y (1≤n≤105,0≤x≤y) — the length of the codes, and two values Alice responds with.
The second line of each test case contains nn integers b1,…,bn (1≤bi≤n+1) — Bob’s guess, where bibi is the i-th color of the guess.
It is guaranteed that the sum of n across all test cases does not exceed 105.
Output
For each test case, on the first line, output “YES” if there is a solution, or “NO” if there is no possible secret code consistent with the described situation. You can print each character in any case (upper or lower).
If the answer is “YES”, on the next line output nn integers a1,…,an (1≤ai≤n+1) — Alice’s secret code, where ai is the i-th color of the code.
If there are multiple solutions, output any.

这道题也需要自创数学算法,但是相对更加复杂。

#include<bits/stdc++.h>
#define LL long long
#define U unsigned
bool isp(int x){
	if(x<2)return 0;
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0) return 0;
	}
	return 1;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
struct shu{
	int val,sam,pos,cor;
}a[200000];
int ji[200000],unuse[200000];
int cmpval(shu x1,shu x2){
	return x1.val<x2.val;
}
int cmpsam(shu x1,shu x2){
	return x1.sam>x2.sam;
}
int cmppos(shu x1,shu x2){
	return x1.pos<x2.pos;
}
int main(){
	int T=read();
	while(T--){
		memset(ji,0,sizeof(ji));
		int n=read(),x=read(),y=read();
		for(int i=0;i<n;i++){
			scanf("%d",&a[i].val);
			a[i].pos=i;
			a[i].sam=1;
			a[i].cor=-1;
			ji[a[i].val]=1;
		}
		int tmp=0;
		for(int i=1;i<=n+1;i++){
			if(ji[i]==0){
				unuse[tmp++]=i;
			}
		}
		sort(a,a+n,cmpval);
		for(int i=1;i<n;i++){
			if(a[i].val==a[i-1].val){
				a[i].sam=a[i-1].sam+1;
			}
		}
		sort(a,a+n,cmpsam);
		tmp=n-y;
		int num,len;
		bool flag=0;
		for(int i=0;i<n;i++){
			if(x>0){
				a[i].cor=a[i].val;
				x--;
				continue;
			}
			if(n-i+n-y<2*a[i].sam){
				printf("NO\n");
				flag=1;
				break;
			}
			num=i,len=n-i;
			break;
		}
		if(flag==1)continue;
		sort(a+num,a+n,cmpval);
		for(int i=num;i<n;i++){
			a[i].cor=(i+len/2<n)?a[(i+len/2)].val:a[(i+len/2+num-n)].val;
		}
		tmp=n-y;
		for(int i=num;i<n;i++){
			if(a[i].cor==a[i].val){
				a[i].cor=unuse[0];
				tmp--;
			}
		}
		for(int i=num;i<n;i++){
			if(tmp>0&&a[i].cor!=unuse[0]){
				a[i].cor=unuse[0];
				tmp--;
			}
		}
		sort(a,a+n,cmppos);
		printf("YES\n");
		for(int i=0;i<n;i++){
			printf("%d ",a[i].cor);
		}
		printf("\n");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值