1. 程式人生 > >牛客Wannafly挑戰賽23 B.遊戲

牛客Wannafly挑戰賽23 B.遊戲

gets -i lose isp 無法 mes 必須 必勝策略 超過

遊戲

題目描述

小N和小O在玩遊戲。他們面前放了n堆石子,第i堆石子一開始有ci顆石頭。他們輪流從某堆石子中取石子,不能不取。最後無法操作的人就輸了這個遊戲。但他們覺得這樣玩太無聊了,更新了一下規則。具體是這樣的:對於一堆有恰好m顆石子的石頭堆,假如一個人要從這堆石子中取石子,設他要取石子數為d,那麽d必須是m的約數。最後還是無法操作者輸。
現在小N先手。他想知道他第一步有多少種不同的必勝策略。一個策略指的是,從哪堆石子中,取走多少顆石子。只要取的那一堆不同,或取的數目不同,都算不同的策略。

輸入描述:

第一行一個整數n。
接下來一行n個整數,分別代表每堆石子的石子數目。
數據保證輸入的所有數字都不超過10^5,均大於等於1,且為整數。

輸出描述:

一行一個整數代表小N第一步必勝策略的數量。

輸入

10
47 18 9 36 10 1 13 19 29 1

輸出

7
鏈接:https://www.nowcoder.com/acm/contest/161/B
來源:牛客網
預處理下SG值,然後枚舉下每堆拿走約數。
技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn = 100005;
 5 int sg[maxn];
 6 int a[maxn];
 7
bool vis[maxn]; 8 9 void getSg() 10 { 11 12 sg[0]=0; 13 for(int i=1;i<maxn;i++) 14 { 15 memset(vis,0,sizeof(vis)); 16 17 for(int j=1;j*j<=i;j++) 18 { 19 if(i%j==0) 20 { 21 vis[sg[i-j]]=1; 22 vis[sg[i-i/j]]=1
; 23 } 24 } 25 26 for(int j=0;j<maxn;j++) 27 { 28 if(vis[j]==0) 29 { 30 sg[i]=j; 31 break; 32 } 33 } 34 } 35 } 36 37 int main() 38 { 39 getSg(); 40 int n; 41 scanf("%d",&n); 42 int sum = 0; 43 for(int i=1;i<=n;i++) 44 { 45 scanf("%d",&a[i]); 46 sum ^= sg[a[i]]; 47 } 48 int ans = 0; 49 for (int i = 1; i <= n; ++i) 50 { 51 sum ^= sg[a[i]]; 52 for (int j = 1; j * j <= a[i]; ++j) 53 { 54 if (a[i] % j == 0) 55 { 56 if (!(sg[a[i] - j] ^ sum)) 57 ans++; 58 if (j * j != a[i] && !(sg[a[i] - a[i] / j] ^ sum)) 59 ans++; 60 } 61 } 62 sum ^= sg[a[i]]; 63 } 64 printf("%d\n",ans); 65 return 0; 66 }
View Code

牛客Wannafly挑戰賽23 B.遊戲