ACdream 1112 Alice and Bob (sg函数的变形+素数筛)

题意:有N个数,Alice 和 Bob 轮流对这些数进行操作,若一个数 n=a*b且a>1,b>1,可以将该数变成 a 和 b 两个数;

或者可以减少为a或b,Alice先,问谁能赢

思路:首先单看对每个数进行除法的操作,我们可以知道其实是在除以每个数的素因子或素因子之间的积

比如 70=2*5*7 我们可以变成 10(2*5)或 14(2*7) 或 35(5*7)或 2 或 5 或 7 或 1 这七种状态

当我们把他们(2,5,7)当作3个石子也就是一堆时,然而实际上我们是将这堆石子进行nim游戏

我拿走一个石子 =》 10(2*5) 我拿走了石子7

14 (2*7) 我拿走了石子5

35 (5*7) 我拿走了石子2

我拿走两个石子 =》 2    我拿走了石子5 和 石子7

5    我拿走了石子2 和 石子7

7    我拿走了石子2 和 石子5

我拿走三个石子 =》 1     我拿走了石子2 和 石子5 和 石子7

接下来我们分析把一个数n=a*b变成 a 和 b ,其实这里上面的思想很像,把它当作石子的分堆

我可以分成             第一种 10(2*5) 和 7

第二种 14(2*7) 和 5

第三种 35(5*7) 和 2

综上所诉,根据正整数唯一分解定理,任何一个正整数x必然有x=(p1^r1)*(p2^r2)*......*(pn^rn)

定义sum=r1+r2+...+rn,这个sum的值就是这堆石子的总数,那么sg=sg[sum1]^sg[susm2]^....

问题又来了? 这个sum我们应该如何求呢?

我们可以通过素数筛得到每一个数的最小质因子,我们得到一个类似于递推的公式

一个正整数的质因子的个数=(这个正整数 / 这个数的最小质因子 所得数) 的质因子个数 + 1(也就是加上这是最小质因子的数量 1)

接下来代码实现就可以了

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 5000000
using namespace std;

int prime[maxn+5],k=0,samll[maxn],sum[maxn];
bool visit[maxn+5];
int sg[105];

void get_prime()
{
    memset(visit,false,sizeof(visit));
    memset(samll,0,sizeof(samll));
    memset(sum,0,sizeof(sum));
    for(int i=2;i<=maxn;i++)
    {
        if(visit[i]==false)
        {
            prime[k++]=i;
            for(int j=i+i;j<=maxn;j+=i)
            {
                visit[j]=true;
                if(samll[j]==0) samll[j]=i;
            }
            samll[i]=i;
        }
    }
    for(int i=2;i<=maxn;i++)
    sum[i]=sum[i/samll[i]]+1;
}

int get(int n)
{
    if(sg[n]!=-1) return sg[n];
    bool vis[105];
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)
    vis[get(n-i)]=true;
    for(int i=1;i<=n/2;i++)
      vis[get(i)^get(n-i)]=true;
    int k;
    for(int i=0;i<105;i++)
    {
        if(vis[i]==false)
        {
           return sg[n]=i;
        }
    }
}

int main()
{
   get_prime();
   memset(sg,-1,sizeof(sg));
   sg[0]=0;
   sg[1]=1;
   for(int i=2;i<=100;i++)
   {
       get(i);
   }
   int n;
   while(cin>>n)
   {
       int ans=0;
       for(int i=1;i<=n;i++)
       {
           int x;
           scanf("%d",&x);
           ans=ans^sg[sum[x]];
       }
       if(ans)
       cout<<"Alice"<<endl;
       else
       cout<<"Bob"<<endl;
   }
   return 0;
}
时间: 2024-08-24 14:29:55

ACdream 1112 Alice and Bob (sg函数的变形+素数筛)的相关文章

ACdream 1112 Alice and Bob(素筛+博弈SG函数)

Alice and Bob Time Limit:3000MS     Memory Limit:128000KB     64bit IO Format:%lld & %llu Submit Status Practice ACdream 1112 Description Here  is Alice and Bob again ! Alice and Bob are playing a game. There are several numbers. First, Alice choose

ACdream 1112 Alice and Bob (博弈&amp;amp;&amp;amp;素数筛选优化)

题目链接:传送门 游戏规则: 没次能够将一堆分成两堆 x = a*b (a!=1&&b!=1)x为原来堆的个数,a,b为新堆的个数. 也能够将原来的堆的个数变成原来堆的约数y.y!=x.进行最后一次操作的人获胜. 分析: 也是一个去石头的游戏,因此我们仅仅须要将全部情况的sg值异或起来就好了. 我们首先来考虑一堆.设这一堆的个数为x: 那么全部的情况就是 (a1,x/a1), (a2,x/a2),...,(an,x/an);或者(a1),(a2),..,(an). 由于数据量比較大,我们朴

ACdream 1112 Alice and Bob (博弈&amp;&amp;素数筛选优化)

题目链接:传送门 游戏规则: 没次可以将一堆分成两堆 x = a*b (a!=1&&b!=1)x为原来堆的个数,a,b为新堆的个数. 也可以将原来的堆的个数变成原来堆的约数y,y!=x.进行最后一次操作的人获胜. 分析: 也是一个去石头的游戏,因此我们只需要将所有情况的sg值异或起来就好了. 我们首先来考虑一堆.设这一堆的个数为x: 那么所有的情况就是 (a1,x/a1), (a2,x/a2),...,(an,x/an);或者(a1),(a2),..,(an). 由于数据量比较大,我们朴素

ZOJ 3666 Alice and Bob (SG博弈)

题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3666 题意: 给一个有向图,然后A和B轮流移动棋子,棋子在每一个位置可以重叠,当某人不能走时,输! 问A和B谁赢 方法: 显然每一局游戏都是独立的,对每一局游戏异或即可 每一局游戏的结果可以用SG求,记忆化搜索之 1 int dfs(int x) 2 { 3 if (sg[x] != -1) return sg[x]; 4 bool vis[maxn]; 5 me

ACdream群赛1112(Alice and Bob)

题意:http://acdream.info/problem?pid=1112 Problem Description Here  is Alice and Bob again ! Alice and Bob are playing a game. There are several numbers.First, Alice choose a number n.Then he can replace n (n > 1)with one of its positive factor but not

zoj 3666 Alice and Bob , SG函数

题意: 在一个有向无环图上,有若干玩具,每人每次只能将一个玩具移动一步,玩具被移动到终点n将不能再被移动了,最后不能移动者输. 组合博弈 SG函数应用 #include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 10000 + 100; int SG[maxn]; vector<int>

Alice and Bob HDU - 4111 (SG函数)

Alice and Bob are very smart guys and they like to play all kinds of games in their spare time. The most amazing thing is that they always find the best strategy, and that's why they feel bored again and again. They just invented a new game, as they

hdu 3032(博弈sg函数)

题意:与原来基本的尼姆博弈不同的是,可以将一堆石子分成两堆石子也算一步操作,其它的都是一样的. 分析:由于石子的堆数和每一堆石子的数量都很大,所以肯定不能用搜索去求sg函数,现在我们只能通过找规律的办法求得sg的规律. 通过打表找规律可以得到如下规律:if(x%4==0) sg[x]=x-1; if(x%4==1||x%4==2) sg[x]=x; if(x%4==3) sg[x] = x+1. 打表代码: #include<iostream> #include<cstdio> #

Light OJ 1296 - Again Stone Game (博弈sg函数递推)

F - Again Stone Game Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Description Alice and Bob are playing a stone game. Initially there are n piles of stones and each pile contains some stone. Alice stars the