“科大訊飛杯”第十七屆同濟大學程序設計預選賽暨高校網絡友誼賽 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;
}

下面是題解的證明:(大佬的做法。。。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章