2011-0011

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

这题是SG函数的应用...

F表示状态转移,那么SG函数的定义为

g(x) = min{n ≥ 0 : n = g(y) for y ∈ F (x)}.

即非后继SG值的最小非负数

g(1) = 0

g(x) = 1, x为质数( 质数的后继只有1, g(1) = 0, 所以g(x) = 1) 

g(x*y) =2,  x,y均为质数(x*y的后继有x,y,0)

g(x*y*z) = 3

由数学归纳法可知

g(x) = x 质因数的个数

然后由SG分解定理就可得 SG = g(a1) xor g(a2) xor g(a3) ... xor g(an)

于是就转成了经典的Nim模型了。

当前状态是后手必胜态当且仅当SG = 0 

每一步决策时就把异或和跟当前的石子数g(ai)进行异或,

如果得到的结果小于当前石子数,则是合法的操作。

稍为详细一点的介绍可以看看 http://blog.csdn.net/SMCwwh/article/details/5027170 

然后就是怎么求这个质因数个数的问题了...(to be continued)...

{{{
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;


#define M 5000001
int minp[M], plist[M];
int prime(int n = M-1){
    int num = 0;
    memset(minp, 0, sizeof(minp));
    for(int i=2; i<=n; i++){
        if (!minp[i]) plist[num++] = i, minp[i] = i;
        for(int j=0;j<num&& i*plist[j]<=n;j++){
            minp[i*plist[j]] = plist[j];
            if (i%plist[j]==0) break;
        }
    }
    return num;
}


int factorize(int n){
    int num = 0;
    while(n!=1){
        n /= minp[n];
        num++;
    }
    return num;
}
int n;
int a[100000],b[100000];
int xorsum;

int main(){
    prime();
while(~scanf("%d",&n)){
        static int T = 1;
        printf("Test #%d: ",T++);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            a[i] =  factorize(a[i]); 
        }

        xorsum = 0;
        for(int i=0;i<n;i++)
            xorsum = xorsum  ^ a[i];
        if (xorsum==0){
            puts("Bob");
        }else{
            printf("Alice ");
            for(int i=0;i<n;i++)
                if ((xorsum ^ a[i]) < a[i]){
                    printf("%d\n",i+1);
                    break;
                }
            }
    }
}
}}}


by Stephen Xu

这题是SG函数的应用...

F表示状态转移,那么SG函数的定义为

g(x) = min{n ≥ 0 : n = g(y) for y ∈ F (x)}.

即非后继SG值的最小非负数

g(1) = 0

g(x) = 1, x为质数( 质数的后继只有1, g(1) = 0, 所以g(x) = 1)

g(x*y) =2, x,y均为质数(x*y的后继有x,y,0)

g(x*y*z) = 3

由数学归纳法可知

g(x) = x 质因数的个数

然后由SG分解定理就可得 SG = g(a1) xor g(a2) xor g(a3) ... xor g(an)

于是就转成了经典的Nim模型了。

当前状态是后手必胜态当且仅当SG = 0

每一步决策时就把异或和跟当前的石子数g(ai)进行异或,

如果得到的结果小于当前石子数,则是合法的操作。

稍为详细一点的介绍可以看看 http://blog.csdn.net/SMCwwh/article/details/5027170

然后就是怎么求这个质因数个数的问题了...(to be continued)...

#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define M 5000001
int minp[M], plist[M];
int prime(int n = M-1){
    int num = 0;
    memset(minp, 0, sizeof(minp));
    for(int i=2; i<=n; i++){
        if (!minp[i]) plist[num++] = i, minp[i] = i;
        for(int j=0;j<num&& i*plist[j]<=n;j++){
            minp[i*plist[j]] = plist[j];
            if (i%plist[j]==0) break;
        }
    }
    return num;
}
int factorize(int n){
    int num = 0;
    while(n!=1){
        n /= minp[n];
        num++;
    }
    return num;
}
int n;
int a[100000],b[100000];
int xorsum;
int main(){
    prime();
while(~scanf("%d",&n)){
        static int T = 1;
        printf("Test #%d: ",T++);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            a[i] =  factorize(a[i]); 
        }
        xorsum = 0;
        for(int i=0;i<n;i++)
            xorsum = xorsum  ^ a[i];
        if (xorsum==0){
            puts("Bob");
        }else{
            printf("Alice ");
            for(int i=0;i<n;i++)
                if ((xorsum ^ a[i]) < a[i]){
                    printf("%d\n",i+1);
                    break;
                }
            }
    }
}

by Stephen Xu