HDOJ1517
題意:從p=1開始,兩個(gè)人輪流乘2~9之間的數(shù),看誰(shuí)最先乘到比給定的數(shù)大。
分析:題目y規(guī)律,但也可以根據(jù)之前所學(xué)的知識(shí)用SG求,雖然我不會(huì)。
先是規(guī)律分析:
p從1開始,每次乘2~9,所以2~9是先手必勝的。然后9~18,是先手必?cái) ?9~18*9是先手必勝,同樣,18*9+1~18*2*9是先手必?cái) ?/p>
容易看出,是以18為規(guī)律的,除18,最后看在那個(gè)區(qū)間。
?
#include <iostream> #include<algorithm> using namespace std; int main() {double n;while(cin>>n){while(n>18){n=n/18; }if(n<=9){cout<<"Stan wins."<<endl;}else{cout<<"Ollie wins."<<endl;}}return 0; }下面就是正常的推算代碼,摘自https://blog.csdn.net/riba2534/article/details/53895389
先把所有可能的乘積從小到大,一一列舉出來(lái)。之后找出乘積小于給定那個(gè)數(shù)的范圍。最后一個(gè)人可以直接*9,所以,從原來(lái)最大數(shù)除9向下找。解釋放在代碼中,這種方法值得學(xué)習(xí)!
#include<iostream> using namespace std; int main() {__int64 a[7000] = { 1 }, min, n;int p[10], sg[7000], i, j, k;for (i = 2; i < 10; p[i] = 0, i++);for (i = 1; i < 7000; i++){for (j = 2, min = -1; j < 10; j++)if (min == -1 || a[p[j]] * j < a[p[min]] * min)min = j;a[i] = a[p[min]] * min;min = a[p[min]] * min;if (a[i] >= 5000000000)break;for (j = 2; j < 10; j++)if (a[p[j]] * j == min)p[j]++;}//從小到大求出所有乘積while (scanf("%I64d", &n) != EOF){for (i = 0; i < 7000; i++){sg[i] = 0;if (a[i] >= n)break;}for (j = i - 1; a[j] * 9 >= n && j >= 0; j--)sg[j] = 1;while (j >= 0){for (k = j + 1; k < i&&a[j] * 9 >= a[k]; k++)if (a[k] % a[j] == 0 && sg[k] == 0)//到最后一個(gè)點(diǎn)需要兩步,不等于0那就是偶數(shù)步,肯定是先手必輸,等于0就是奇數(shù)步,先手必贏//第一個(gè)判斷是因?yàn)橐粋€(gè)一個(gè)往下除,所以必須要整除,這里有點(diǎn)搜索的味道了,在x~x*9的范圍里搜索除整除數(shù),//并且是否為奇數(shù)步,有一個(gè)為奇數(shù)步那就是先手必勝,沒(méi)有奇數(shù)步,全是偶數(shù)步那就是先手必輸//所以先手是奇數(shù)步可以轉(zhuǎn)換成偶數(shù)步,因?yàn)榕紨?shù)步是0,所以它后面如果能整除那么全都是1,這就回到了PN問(wèn)題。偶數(shù)步只能轉(zhuǎn)換為奇數(shù)步,//而奇數(shù)步能找到一個(gè)轉(zhuǎn)換為偶數(shù)步的。{sg[j] = 1;break;}j--;}puts(sg[0] ? "Stan wins." : "Ollie wins.");}return 0; }?
超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
- 上一篇: HDOJ1907 SG问题
- 下一篇: 线索树