题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32746
题意:有一个n*m(1<=n,m<=50)矩阵,每个元素均为2~10000之间的正整数,两个游戏者轮流操作。每次可以选一行中的1个或者大于1的整数,把他们中的每个数都变成它的某个真因子,比如12可以边长1,2,3,4或者6,不能操作的输。
分析:考虑每个数包含的素因子个数(比如12=2*2*3包含3个素因子),则让一个数“变成它的素因子”等价于拿掉它的一个或者多个素因子。这样每一行对应一个正整数x(x表示可以拿的素因子总个数),可以拿某一行的任意多个因子。这就转化成基本的Nim博弈了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 103;
int prime[maxn],nprime,cnt[maxn*maxn];
bool isprime[maxn];
void doprime()
{
nprime=0;
fill(isprime+2,isprime+maxn,true);
for(int i=2;i<maxn;i++)
if(isprime[i])
{
prime[nprime++]=i;
for(int j=2*i;j<maxn;j+=i)
isprime[j]=false;
}
}
void work()
{
doprime();
memset(cnt,0,sizeof(cnt));
for(int i=2;i<=10000;i++)
{
int temp=i;
for(int j=0;j<nprime;j++)
{
if(temp%prime[j]==0)
{
cnt[i]=cnt[temp/prime[j]]+1;
temp=1;
break;
}
}
if(temp>1)
cnt[i]=1;
}
}
int main()
{
work();
int ncase,n,m,i,j,ans,x;
scanf("%d",&ncase);
for(int T=1;T<=ncase;T++)
{
scanf("%d%d",&n,&m);
ans=0;
for(i=1;i<=n;i++)
{
int cal=0;
for(j=1;j<=m;j++)
{
scanf("%d",&x);
cal+=cnt[x];
}
ans^=cal;
}
printf("Case #%d: %s\n",T,(ans?"YES":"NO"));
}
return 0;
}