CodeForces 317 D.Game with Powers(博弈论)

Description

两个人 Vasya Petya 玩游戏,从 1 ~ n中取数, Vasya 先取,如果 x 之前已经被取过则所有x的正整数次幂都不能被取,谁先没有数字可以取谁输,问谁赢

Input

一个正整数 n 1n109

Output

输出胜者

Sample Input

1

Sample Output

Vasya

Solution

如果 x 不是任一y(<x)的正整数次幂,则把所有 x 的正整数次幂的数归为一类记为Pow(x),显然任意两类不交,且任一类的规模不超过 log2n ,那么问题变成若干相同的子问题,暴力打表求出 SG(1) ~ SG(30) ,注意到如果 x>n ,那么 Pow(x) 规模是1,故只需要求出所有 xn Pow(x) 的规模对应的SG值异或起来,再统计一下所有 x>n 且不是任意 y(<x) 的正整数次幂的数的个数,奇数就对答案异或1( SG(1)=1 )

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 33
int sg[maxn]={0,1,2,1,4,3,2,1,5,6,2,1,8,7,5,9,8,7,3,4,7,4,2,1,10,9,3,6,11,12,14};
map<int,int>m;
int solve(int n)
{
    if(n==0)return 0;
    if(m.find(n)!=m.end())return m[n];
    int f[maxn];
    memset(f,0,sizeof(f));
    for(int i=1;i<=30;i++)
        if(n&(1<<i))
        {
            int tn=n;
            for(int j=i;j<=30;j+=i)
                if(n&(1<<j))
                    tn^=(1<<j);
            f[solve(tn)]=1;
        }
    for(int i=0;;i++)
        if(!f[i])return m[n]=i;
}
void init()
{
    m.clear();
    sg[0]=0;
    for(int i=1;i<=30;i++)sg[i]=solve((1<<(i+1))-2);
}
set<int>s;
int vis[55555];
int main()
{
    //init();
    //for(int i=0;i<=30;i++)printf("%d ",sg[i]);
    int n;
    while(~scanf("%d",&n))
    {
        s.clear();
        memset(vis,0,sizeof(vis));
        int ans=0;
        for(ll i=2;i*i<=n;i++)
            if(!vis[i])
            {
                int num=0;
                for(ll j=i;j<=n;j*=i)
                {
                    num++,s.insert(j);
                    if(j*j<=n)vis[j]=1;
                }
                //printf("num=%d\n",num); 
                ans^=sg[num];
            }
        if((n-s.size())&1)ans^=1;
        printf("%s\n",ans?"Vasya":"Petya");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值