[bzoj3492]Binary Dodgeball

来源:互联网 发布:ios同步请求数据 编辑:程序博客网 时间:2024/06/05 20:51

结论

我把乘2^k变成除以的话和原游戏当然是等价的。
这样的话我们把每个数二进制都写出来,每次就是去掉末尾几个0。
按照除lowbit部分分组,不同组之间互相独立。
每组的游戏可以这样描述:
有一群石子堆,每次从一个石子堆拿走至少一颗石子,若存在两堆相同的石子堆,则一起移走。
没有后面那个的话很容易知道就是nim游戏。
但其实我们可以把移走的两堆绑在一起,那么一个人操作其中一堆,另一个人就对着另外一堆进行相同操作,游戏局面不变(大概用了阶梯nim的思想)
这样思考这两堆石子堆就可以不移走。
那就是彻彻底底的nim游戏。
因此我们知道后手必胜就是上述过程异或和为0。
求解我们考虑二分+判定,于是问题变成了求<=N的有多少n合法。
这里为了防止懵逼,来定义一下合法的n。
对于一个1<=i<=n
i的贡献是末尾有多少连续0(在二进制下,如10100贡献为2)
把贡献异或起来,是0那么n是合法。

数位DP

我们考虑对于一个n,k的贡献。(即所有贡献为k的数有多少个,只关心奇偶性即可)
贡献k那么说明二进制下最末是100……0,有k个0。
这样的数有多少个呢?n2kn2k+1
我们只关心这个式子的奇偶性。可以发现就是n的第k位和第k+1位是否相同,相同就是奇数否则是偶数。
这样就好算了!
设f[i,j,k,0~1]表示做完第i位,第i位是j,当前贡献异或和为k,目前这个数是=N的前i位还是<N的前i位。
转移也很简单。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxd=50,mx=64;ll l,r,mid;int f[maxd+10][2][100][2],ws[maxd+10];int i,j,k,t,n,m;int check(ll N){    int i,j,k,l,r,t;    fo(i,0,maxd)        fo(j,0,1)            fo(k,0,mx)                fo(t,0,1)                    f[i][j][k][t]=0;    ll K=N;    fo(i,0,maxd){        ws[i]=K%2;        K/=2;    }    if (ws[maxd]==1){        f[maxd][1][0][1]=1;        f[maxd][0][0][0]=1;    }    else f[maxd][0][0][1]=1;    fd(i,maxd-1,0)        fo(j,0,1)            fo(k,0,mx)                fo(t,0,1){                    if (j<ws[i]){                        f[i][j][k][0]+=f[i+1][t][k^(i*(j!=t))][0]+f[i+1][t][k^(i*(j!=t))][1];                    }                    else if (j==ws[i]){                        f[i][j][k][0]+=f[i+1][t][k^(i*(j!=t))][0];                        f[i][j][k][1]+=f[i+1][t][k^(i*(j!=t))][1];                    }                    else{                        f[i][j][k][0]+=f[i+1][t][k^(i*(j!=t))][0];                    }                }    r=0;    fo(i,0,1)        fo(j,0,1)            r+=f[0][i][0][j];    return r-1;}int main(){    scanf("%d",&m);    l=0;r=62064730374;    while (l<r){        mid=(l+r)/2;        if (check(mid)<m) l=mid+1;else r=mid;    }    check(1);    printf("%lld\n",l);}
0 0
原创粉丝点击