Codeforces Round #658 (Div. 2) A-D

A:显然都取长度为1,不仅长度优,而且更容易构造。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int vs[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int T;
	  cin>>T;
	 while(T--)
	 {
	 	int n,m,x;
	 	memset(vs,0,sizeof(vs));
	 	int fg=-1;
	 	cin>>n>>m;
	 	for(int i=1;i<=n;i++)cin>>x,vs[x]=1;
	 	for(int i=1;i<=m;i++)
	 	{
	 		cin>>x;
	 		if(vs[x])fg=x;
		 }
		if(fg==-1)cout<<"NO"<<endl;
		else {
			cout<<"YES"<<endl<<1<<" "<<fg<<endl;
		}
	  } 
	return 0;
}

B:简单的博弈。堆数为1是无法控制的。

而一点谁先手取到堆数不唯一,他直接可以控制是取完这堆还是取到只剩一个:

以便于他先手到下一堆堆数不为1的石子,直到可以取胜的最后一堆不为1的石子。

所以只要看第一堆不为1的石子距离第一堆石子的堆数即可。(全为1特判下就行)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int T;
	  cin>>T;
	 while(T--)
	 {
	 	int n;
	 	cin>>n;
	 	for(int i=1;i<=n;i++)cin>>a[i];
	 	int nm=0;
	 	for(int i=1;i<=n;i++)
	 	{
	 		if(a[i]==1)nm++;
	 		else break;
		}
		if(nm==n)
		{
			if(n&1)cout<<"First"<<endl;
			else cout<<"Second"<<endl;
		}
		else
		{
			if(nm&1)cout<<"Second"<<endl;
			else cout<<"First"<<endl;
		}
	 }
	return 0;
}

C2:每个字符可以变两次,显然都先变第一个字符,再变整个即可。

从后往前依次变好每一个字符。

这题的瓶颈在于不能每次都翻转,不然会T。

我们仔细观察发现:若每次i都旋转[1-i]字符,则最终字符的排列为:[……n-2,3,n-1,2,n,1];

然后再记录字符翻转次数即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
char a[M],b[M];
int id[M],id2[M];
 
void cg(int x)
{
	if(a[x]=='1')a[x]='0';
	else a[x]='1';
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		scanf("%d",&n);
		scanf("%s%s",a,b);
		for(int i=0;i<n;i++)id[i]=0;
		vector<int>p;
		int sz=0;
		id[0]=0;
		for(int i=n-1;i>=0;i-=2)id[i]=++sz;
		int t=0;if(id[t])t++;
		for(int i=t;i<n;i+=2)id[i]=++sz;
		for(int i=1;i<n;i++)id2[i]=id[i-1];id2[0]=id[0];
		int nm=0;
		for(int i=n-1;i>=0;i--)
		{
			char tp=a[id[i]-1];
			if(nm&1)
			{
				if(tp=='1')tp='0';
				else tp='1';
			}
			if(tp==b[i])p.pb(0),cg(id[i]-1);
			p.pb(i);nm++;
		}
		printf("%d ",p.size());
		for(auto x:p)printf("%d ",x+1);
		printf("\n");
	}
	return 0;
}

D:

仔细观察发现:a数组中最大的数和其后面的数一定是连在一起的,否则不会最大的数放前面。

然后把这些数绑定成长度为x的块。剩下的新的a数组重复这个操作。

最后得到sz个块。这要这些块能拼凑成长度为n的数组。就说明能够造出。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 4000+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M],b[M];
int dp[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	  int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		set<int>s;
		for(int i=1;i<=2*n;i++)
			cin>>a[i],s.insert(i);
		int sz=0,nm=0;;
		for(int i=2*n;i>=1;i--)
		{
			int tp=*(--s.end());
			if(tp==a[i])
			{
				nm++;
				b[++sz]=nm;
				nm=0;
			}
			else nm++;
			s.erase(a[i]);
		}
	//	cout<<":iojkojk "<<endl;
		for(int j=0;j<=n;j++)dp[j]=0;
		dp[0]=1;
		for(int i=1;i<=sz;i++)
		{
		//	cout<<"-   "<<i<<" "<<b[i]<<endl;
			for(int j=n;j>=b[i];j--)
				dp[j]+=dp[j-b[i]];
				//cout<<i<<" - "<<j<<" = "<<dp[j]<<endl;;
		}
		if(dp[n])cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	} 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值