丟史蒂芬妮“盛大遊戲杯”第15屆上海大學程式設計聯賽夏季賽暨上海高校金馬五校賽
丟史蒂芬妮
釋出時間: 2017年7月9日 20:20 最後更新: 2017年7月10日 21:11 時間限制: 1000ms 記憶體限制: 128M
有一天,空和白很無聊,決定玩盛大遊戲,考慮到兩個人玩,他們隨便掏了一個遊戲出來:在一個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
資料量很大,建議使用scanf或關閉cin的同步。
記憶化搜尋
可以將問題轉化成取石子:
有兩堆石子,數量分別為n個和m個(n*m的棋盤),每次可以取走其中一堆質數個石子,
也可以同時取走兩堆數量相同的質數個石子,到誰不能取誰失敗
很明顯,(0, 0),(0,1),(1,0)都是必輸態
那麼(2,0),(0,2),(2,1),(0,3),(3,0),(0,3),……,(k,1),(1,k),(k+1,0),(0,k+1)(k為質數)都是必贏態,因為它們都可以一步取到必輸態
知道可以這樣處理就好辦了,因為n和m就500,直接記憶化搜尋預處理
dp[x][y]==0表示(x,y)狀態必輸,dp[x][y]==1表示(x,y)狀態必贏
那麼如果(x,y)的前驅只要有一個是必輸態,那麼(x,y)就是必贏態,否則必輸
程式碼一:
#include<stdio.h>
#include<string.h>
int k=0, dp[505][505], pri[505], jud[505] = {1,1};
int Sech(int x, int y)
{
int i;
if(dp[x][y]!=-1)
return dp[x][y];
for(i=1;i<=k&&pri[i]<=x;i++)
{
if(Sech(x-pri[i], y)==0)
{
dp[x][y] = 1;
return dp[x][y];
}
}
for(i=1;i<=k&&pri[i]<=y;i++)
{
if(Sech(x, y-pri[i])==0)
{
dp[x][y] = 1;
return dp[x][y];
}
}
for(i=1;i<=k&&pri[i]<=y&&pri[i]<=x;i++)
{
if(Sech(x-pri[i], y-pri[i])==0)
{
dp[x][y] = 1;
return dp[x][y];
}
}
dp[x][y] = 0;
return dp[x][y];
}
int main(void)
{
int T, n, i, j, m;
for(i=2;i<=500;i++)
{
if(jud[i])
continue;
pri[++k] = i;
for(j=i*i;j<=500;j+=i)
jud[j] = 1;
}
scanf("%d", &T);
memset(dp, -1, sizeof(dp));
while(T--)
{
scanf("%d%d", &n, &m);
dp[0][0] = dp[1][0] = dp[0][1] = dp[1][1] = 0;
if(Sech(n-1, m-1))
printf("Sora\n");
else
printf("Shiro\n");
}
return 0;
}
程式碼二:
#include<bits/stdc++.h>
using namespace std;
const int maxn= 500;
int prime[maxn+5]= {0};
int num_prime=0;
bool isprime[maxn+5]= {1,1};
int vis[maxn+5][maxn+5];
void init()
{
for(int i=2; i<maxn+5; i++)
{
if(!isprime[i])
prime[num_prime++]=i;
for(int j=0; j<num_prime&&i*prime[j]<maxn+5; j++)
{
isprime[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
memset(vis,0,sizeof(vis));//1:必勝 2:必敗
vis[1][1]=2;
for(int i=1; i<=maxn; i++)
{
for(int j=1; j<=maxn; j++)
{
if(vis[i][j]==0)
{
vis[i][j]=2;
}
if(vis[i][j]==2)
{
for(int k=0; ; k++)
{
if(i+prime[k]>maxn&&j+prime[k]>maxn)
break;
if(i+prime[k]<=maxn)
{
vis[i+prime[k]][j]=1;
}
if(j+prime[k]<=maxn)
{
vis[i][j+prime[k]]=1;
}
if(i+prime[k]<=maxn&&j+prime[k]<=maxn)
{
vis[i+prime[k]][j+prime[k]]=1;
}
}
}
}
}
}
int main()
{
init();
int n,m;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
if(vis[n][m]==1) puts("Sora");
else puts("Shiro");
}
return 0;
}