题目唯一的难点在于dp中某些状态的转移不好用。原因是有些状态不能用int表示,比如002这种的数,但容易知道第一个是0的
都是必胜态,转移时,比如201,能转移乘001,如果不考虑前导0,会到1,而1是必输态,这样201会是必胜态,但是001是必胜态
,所以要判断前面的数字去掉之后,有没有前导0;(s-P[up][i]+P[j][i])>P[1][i-1](判断前导0的)sg函数其实不用int,
用bool就行。dp即为sg函数值。
#include <cstdio> #include <cstring> using namespace std; bool dp[1000000]; int up; bool ok; int P[10][8]; void pre(){ for(int j=0; j<=9; ++j) { P[j][1]=j; P[j][2]=j*10; P[j][3]=j*100; P[j][4]=j*1000; P[j][5]=j*10000; P[j][6]=j*100000;
P[j][7]=j*1000000;} } inline int getdigit(int s, int n){ int r=10; for(int i=1; i<n; ++i) r*=10; s%=r; r/=10; return s/r; } inline void work(int s){ int l,t=s; for(l=1; t/=10; ++l); for(int i=1; i<=l; ++i){ up=getdigit(s,i); if(up==0){ if(dp[s/P[1][i+1]]==0) dp[s]=1; } else for(int j=0; j<up; ++j){ if(i==l&&up==1); else{ if((s-P[up][i]+P[j][i])>P[1][i-1]&&dp[s-P[up][i]+P[j][i]]==0) { dp[s]=1; break;} } } } } int main(){ pre(); dp[0]=1; for(int i=1; i<1000000; ++i) work(i); char a[7]; while(gets(a)){ int s=0; if(a[0]=='0') { s=0; } else for(int i=0; a[i]; ++i) s=s*10+a[i]-'0'; if(dp[s]==0) printf("No/n",s); else printf("Yes/n"); } }