• bzoj3576[HNOI2014]江南乐


    首先整个局面的SG值等于各个独立子局面的SG值异或和,于是只要求SG(1~100000)了。考虑将一堆i个石头分成j堆时,它的后继状态是 {((j-i mod j))((i/j))((i mod j))((i/j+1))},这个后继状态的SG值同样等于这j个局面的SG异或和,于是要计算SG(i)就只需枚举将它分成j=1~i堆(j>i是没有意义了的,在j=i时已经考虑到了),然后把后继状态的SG取mex即可。
    于是就有(O(n^2))的算法:

    for(int i=1;i<F;++i) SG[i]=0;
    for(int i=F;i<=100000;++i)
    {
    	for(int j=2;j<=i;++j)
    	{
    		int num=(j-i%j)&1,num1=(i%j)&1;
    		int sg=(num*SG[i/j])^(num1*SG[i/j+1]);
    		vis[sg]=1; stk[++top]=sg;
    	}
    	for(int j=0;;++j) if(!vis[j]) {SG[i]=j;break;}
    	while(top) vis[stk[top]]=0,top--;
    }
    for(int cas=1;cas<=T;++cas)
    {
    	n=read(); int ans=0;
    	for(int i=1;i<=n;++i) a[i]=read(),ans^=SG[a[i]];
    	printf("%d ",!(!ans));
    }
    

    然后容易想到这个可以分块优化,对于一段(i/j)相同的j,(j-i mod j)(i mod j)有一个是公差为偶数的等差数列,一个是公差为奇数的等差数列,所以只需要考虑一段(i/j)相同的j的其中两个即可。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define P puts("lala")
    #define cp cerr<<"lala"<<endl
    #define fi first
    #define se second
    #define pb push_back
    #define ln putchar('
    ')
    using namespace std;
    inline int read()
    {
    	char ch=getchar();int g=1,re=0;
    	while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
    	return re*g;
    }
    typedef long long ll;
    typedef pair<int,int> pii;
    
    const int N=125;
    const int M=100050;
    int a[N],F,n;
    int SG[M],stk[M],top=0;
    bool vis[M];
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    #endif
    	int T=read(); F=read();
    	for(int i=1;i<F;++i) SG[i]=0;
    	for(int i=F;i<=100000;++i)
    	{
    		for(int l=2,r;l<=i;l=r+1)
    		{
    			r=i/(i/l);
    			int num=0,num1=0,sg=0;
    			num=(l-i%l)&1; num1=(i%l)&1;
    			sg=(num*SG[i/l])^(num1*SG[i/l+1]);
    			vis[sg]=1;
    			stk[++top]=sg;
    
    			if(l!=r)
    			{
    				l++;
    				num=(l-i%l)&1; num1=(i%l)&1;
    				sg=(num*SG[i/l])^(num1*SG[i/l+1]);
    				vis[sg]=1;
    				stk[++top]=sg;
    			}
    		}
    		for(int j=0;;++j) if(!vis[j]) {SG[i]=j;break;}
    		while(top) vis[stk[top]]=0,top--;
    	}
    	for(int cas=1;cas<=T;++cas)
    	{
    		n=read();
    		int ans=0;
    		for(int i=1;i<=n;++i) a[i]=read(),ans^=SG[a[i]];
    		printf("%d ",!(!ans));
    	}
    	return 0;
    }
    
  • 相关阅读:
    今天早上打算去菜市场看看是否开张
    昨天晚上雨岳阳通话后,晚上睡着肚子咕咕叫
    已经一周没有开锅了
    今天早上6:00起来,每天晚上回来6点多已经天黑
    其实值班也是一个说法
    感觉每天虽然没有做什么,但是就是觉得睡不够
    现在进入秋季,上海也是在20度左右
    mysql 下 计算 两点 经纬度 之间的距离 含具体sql语句
    java解析xml的几种方式
    myeclipse安装svn插件的多种方式
  • 原文地址:https://www.cnblogs.com/thkkk/p/8677671.html
Copyright © 2020-2023  润新知