有一天,空和白很无聊,决定玩盛大游戏,考虑到两个人玩,他们随便掏了一个游戏出来:在一个n∗m 的棋盘上,首先把史蒂芬妮·多拉放在左上角(1,1) 的位置。每次一个人可以将她往下,往右,往右下丢一格。当前回合,谁不能丢史蒂芬妮,谁就输了。(注意,不可以把活人丢出棋盘啦!)游戏总是空先手。
白说,这是一个垃圾游戏!我们每次把史蒂芬妮丢素数个位置吧!(换句话说,每次丢2 或3 或5 或7 或…格)空答应了。
我们都知道,空和白都很聪明,不管哪方存在一个可以必胜的最优策略,都会按照最优策略保证胜利。
玩了一局,空已经知道了这个游戏的套路,现在他决定考考你,对于给定的n 和m ,空是赢是输?如果空必胜,输出“Sora”(无引号);反之,输出“Shiro”(无引号)。
第一行有一个T表示数组组数,1<=T<100000
从第二行开始,每行为棋盘大小,n
、m
分别表示行列。
1=<n<=500
,1=<m<=500
对于每组数据,按题目要求输出。
复制
4 1 1 2 2 10 10 30 30
Shiro Shiro Shiro Sora
【思路】
打表预处理。
对于每个位置dp[i][j],若所有可能的下一位置都是必胜态,则当前位置为必败态;若可能的下一位置有一个是必败态,则当前位置是必胜态。从后往前递推。
【Accepted】
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 const int maxn=505; 8 typedef long long ll; 9 const ll mod=1e9+7; 10 bool isprime[maxn]; 11 int prime[maxn]; 12 int dp[maxn][maxn]; 13 int main() 14 { 15 memset(isprime,true,sizeof(isprime)); 16 memset(dp,0,sizeof(dp)); 17 for(int i=2;i<=maxn;i++) 18 { 19 if(isprime[i]) 20 { 21 for(int j=i*2;j<=500;j+=i) 22 { 23 isprime[j]=false; 24 } 25 } 26 } 27 int cntp=0; 28 for(int i=2;i<=maxn;i++) 29 { 30 if(isprime[i]) 31 { 32 prime[cntp++]=i; 33 } 34 } 35 for(int i=1;i<=maxn;i++) 36 { 37 for(int j=1;j<=maxn;j++) 38 { 39 for(int k=0;k<cntp;k++) 40 { 41 if(i>prime[k]) 42 { 43 dp[i][j]|=!dp[i-prime[k]][j]; 44 } 45 if(j>prime[k]) 46 { 47 dp[i][j]|=!dp[i][j-prime[k]]; 48 } 49 if(i>prime[k]&&j>prime[k]) 50 { 51 dp[i][j]|=!dp[i-prime[k]][j-prime[k]]; 52 } 53 } 54 } 55 } 56 int T; 57 scanf("%d",&T); 58 int n,m; 59 while(T--) 60 { 61 scanf("%d%d",&n,&m); 62 if(dp[n][m]) 63 { 64 puts("Sora"); 65 } 66 else 67 { 68 puts("Shiro"); 69 } 70 } 71 return 0; 72 }