題目鏈接:傳送門
游戲規則:
沒次可以將一堆分成兩堆 x = a*b (a!=1&&b!=1)x為原來堆的個數,a,b為新堆的個數。
也可以將原來的堆的個數變成原來堆的約數y,y!=x。進行最後一次操作的人獲勝。
分析:
也是一個去石頭的游戲,因此我們只需要將所有情況的sg值異或起來就好了。
我們首先來考慮一堆。設這一堆的個數為x;
那麼所有的情況就是
(a1,x/a1), (a2,x/a2),...,(an,x/an);或者(a1),(a2),..,(an)。
由於數據量比較大,我們樸素的找約數肯定會超時。然後仔細分析一下這個問題。因為我
們都是圍繞著約數來進行操作,那麼也就相當於在對他的素因子的個數進行操作。
x=a1^r1*a2^r2*...*an^rn;設sum = r1+r2+...+rn.
然後所有的情況就可以表示為:
(1,sum-1),(2,sum-2),...(sum/2,sum-sum/2)或者(1),(2),...(n-1)
這樣就大大減小了數據的范圍。然後在計算sum的時候我們可以這樣計算。
設一個數為x,他的最小的素因子為y.則sum[x] = sum[x/y] + 1;
代碼如下:
#include#include #include #include using namespace std; const int maxn = 5000010; int prime[maxn],cnt; bool isprime[maxn]; int fac_num[maxn]; int min_fac[maxn]; int sg[100]; void GetPirme(){ cnt=0; memset(isprime,0,sizeof(isprime)); memset(fac_num,-1,sizeof(fac_num)); memset(min_fac,-1,sizeof(min_fac)); for(int i=2;i