CodeForces 87C Interesting Game (博弈论+数论)*

#include
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll unsigned long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
const int  maxn =1e5+5;
const int mod=9999991;
const int ub=1e6;
const double e=2.71828;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:最开始有一堆石子,
定义一种操作,可以把一堆石子变成为
连续数字(和相同)代表的堆。

首先要用dp思想去考虑,
假设扫描到i位置,令:k,k+1,...k+j-1(共j个数字),
和为i,那么我们可以得到:j*(2*k+j-1)=2*i,
不难发现j<2*k+j-1,那么我们只要扫描根号2i内的因子,
判断其是否存在k即可。

找到j和k后,我们需要动态维护sg函数前缀和,开一个数组维护下就行,异或性质允许。
对于得到的新的sg值直接丢到f数组里面,为了节省时间把特判条件定为是否等于i,
最后通过f数组更新dp值(就是sg值),在中途如果发现sg值有0,立马更新答案即可。

时间复杂度O(n^(3/2))
*/
int dp[maxn],sum[maxn],ans[maxn],f[maxn];
int n,INF;

int main(){
    scanf("%d",&n);
    mst(ans,0xf);INF=ans[0];
    for(int i=1;i<=n;i++){
        int tmp=2*i;
        for(int j=2;j*j<=tmp;j++) if(tmp%j==0){
            int k=tmp/j+1-j;
            if(k%2) continue;
            k>>=1;
            if(k<1) continue;
            int ret=sum[k-1]^sum[k+j-1];
            f[ret]=i;
            if(!ret)  ans[i]=min(ans[i],j);///必胜的条件
        }
        for(int j=0;;j++){///sg值不一定只有0和1,最好还是保险起见(虽然手动模拟时候并不觉得)
            if(f[j]!=i){
                dp[i]=j;
                break;
            }
        }
        sum[i]=sum[i-1]^dp[i];
    }
    ///for(int i=1;i<=n;i++) cout<

 

你可能感兴趣的:(Codeforces习题集,概率论/博弈论,动态规划之博弈DP)