“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络友谊赛 G 硬币游戏Ⅲ SG函数 /Mutli-SG 游戏 终于补完了……

这题是Mutli-SG 的变形。

本质还是SG函数。

不考虑算法复杂度来看:

每个局面的SG值等于只有一个硬币的SG值的异或和。

我们这样想:把长度为n的字符串当成n堆石子。

从左往右第i位为1表示第i堆有i个石子。

一次操作相当于把第x堆石子分成  若干堆(小于第x堆大小)。(会出现某一位有2个正面朝上的硬币,即2个堆大小相同的堆,但是他们SG的异或和为0,相当于消去他们,即变成背面朝上)

有了上面的转化,我们就能用SG函数求解了。

暴力打出SG函数的表是n*n*k的复杂度。

正常人的做法:打表发现,SG[i]=min(lowbit(i),2^w);  2^w<=k<2^(w+1)

然后O1打出SG,直接搞即可。

下面程序附带打表

#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 = 1e+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
int SG[M];
int vs[M];
char s[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n,k;
  	cin>>n>>k;
//  	SG[1]=1;//只有一个SG==0的可达 
//  	for(int i=2;i<=100;i++)
//  	{
//  		memset(vs,0,sizeof(vs));
//  		vs[0]=1;//翻一枚硬币 
//  		for(int j=2;j<=k;j++)//翻几枚硬币 
//  		{
//  			if(i-j+1<1)break;
//  			int tp=0;
//  			for(int q=i-j+1;q<i;q++)tp^=SG[q];
//  			vs[tp]=1;
//		}
//		for(int j=1;j<=100;j++)if(!vs[j]){
//			SG[i]=j;
//			break;
//		}
//	}
//	for(int i=1;i<=100;i++)
//	{
//		cout<<i<<"  "<<SG[i]<<" "<<(i&(-i))<<endl;
//	}
	int ans=1;
	while(k>1)
	{
		k/=2;
		ans*=2;
	}
	for(int i=1;i<=n;i++)
		SG[i]=min(-i&i,ans);
	cin>>s;
	int tp=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i-1]=='1')tp^=SG[i];
	}
	if(tp==0)cout<<"No"<<endl;
	else cout<<"Yes"<<endl;
	return 0;
}

下面是题解的证明:(大佬的做法。。。)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值