找了幾道簡單的熱熱身,感受本身算法仍是記不住,能描述,不會寫,應該是練少了的緣故。算法
今天一道題交了好幾遍纔對啊,明明是很簡單的題啊啊啊啊啊,算了,先回憶一下心路歷程。ide
題目是這樣的學習
問題描述
棟棟正在和同窗們玩一個數字遊戲。
遊戲的規則是這樣的:棟棟和同窗們一共n我的圍坐在一圈。棟棟首先說出數字1。接下來,坐在棟棟左手邊的同窗要說下一個數字2。再下面的一個同窗要從上一個同窗說的數字往下數兩個數說出來,也就是說4。下一個同窗要往下數三個數,說7。依次類推。
爲了使數字不至於太大,棟棟和同窗們約定,當在心中數到 k-1 時,下一個數字從0開始數。例如,當k=13時,棟棟和同窗們報出的前幾個數依次爲:
1, 2, 4, 7, 11, 3, 9, 3, 11, 7。
遊戲進行了一下子,棟棟想知道,到目前爲止,他全部說出的數字的總和是多少。
輸入格式
輸入的第一行包含三個整數 n,k,T,其中 n 和 k 的意義如上面所述,T 表示到目前爲止棟棟一共說出的數字個數。
輸出格式
輸出一行,包含一個整數,表示棟棟說出全部數的和。
樣例輸入
3 13 3
樣例輸出
17
樣例說明
棟棟說出的數依次爲1, 7, 9,和爲17。
數據規模和約定
1 < n,k,T < 1,000,000;測試
題目就是這樣。因爲T什麼的仍是很大的,把這些數據都保存下來不現實,固然一個優秀的ACMer也根本不會用都保存下來的爛辦法(雖然我連ACMer都不是)。若是不保存數據,很容易就能想到必需要依靠規律,(我怎麼感受我會作的只有找規律的,不開心)網站
規律很容易就想出來了,根據題目描述,那個數列(1,2,4,7,11)在全部狀況下都是固定的,只不過每種狀況被模的數不一樣,以及被棟棟輪到的數不一樣。很容易有遞推公式:f(n) = f(n-1)+n-1;(這裏的n是下標,不是題目中的人數)那麼哪一個位置是棟棟該說的呢?容易知 i % n == 1的那個位置是棟的。由此我寫出了下面的代碼。spa
1 #include<stdio.h> 2 3 int main() 4 { 5 int n,k,T; 6 int i = 1,x = 1,x0 = 1; 7 int sum = 1; 8 cin >> n>>k>>T; 9 for(i=2;i <= (T - 1)*n+1;i++) 10 { 11 x = x +i - 1; 12 if(x > k)x = x%k; 13 if(i % n == 1)sum += x; 14 } 15 cout<<sum<<endl; 16 17 return 0; 18 }
結局顯而易見,超時。T與n很大的時候(甚至不太大的時候)由於for循環裏面是T*n,超時是必然的。code
當時我圖省事,上網學習了一下。有人和我有同樣的問題,而且有一我的回答他,只關注棟棟的數據便可,沒必要每一個數據都要求出來。(番外:回答這個問題的是我同窗啊,我在問問題的時候別人已經開始回答問題了啊!!別問我怎麼知道的,誰叫他全部社交網站都用的是同一張本身的照片呢。)blog
既然只關注棟棟的數據,遞推公式就要從新推理了。以題目中3 13 3的數據分析。易知 f(n) = f(n - 3) + 3n - 6;這裏的n就是下標的意思,爲了不誤會換成 f(a) = f(a - 3) + 3a - 6;題目中是三我的一循環,若是是n我的一循環呢?遞推公式更具通常性。可是,這時,好死不死,我把遞推公式改爲了 f(a) = f(a - n) + 3a - 6;這顯然是不對的,3a - 6也是要改的啊姑娘。當時我沒想到,興沖沖的就改好交了。3a - 6是啥呢,是a - 1 + a - 2 + a - 3;擴展到n是a - 1 + a - 2 + a - 3 +...+a - n;也就是a*n + n(n + 1)/2;遞推公式是f(a) = f(a - n) + a*n + n(n + 1)/2; T是棟報數的次數,用 i 來循環(1,2,3...T)a與i的關係是a = i * n + 1;稍改程序便可。遊戲
不過,個人程序仍是不對,無非就是這兩句程序x0 = x0 + (i * n + 1)* n - n*(n + 1)/2; x = x0%k; sum += x;這個看似正確,其實在對x0取模之後還要再賦值給x0,以便下次使用。由於 sum %d = (a%d +b%d)%d !=(a+b)%d,必定要根據題目中的規定來。改了以後仍是不對,我頹了,感受心累,然而,此時我靈光一現,把數據都改成longlong類型,而後就正確了!!!代碼以下,代碼中大量的註釋記錄了個人思考過程,一點也不捨得刪掉。ci
1 #include<stdio.h> 2 3 int main() 4 { 5 long long n,k,T; 6 long long i = 1,x = 1,x0 = 1; 7 long long sum = 1; 8 scanf("%I64d%I64d%I64d",&n,&k,&T); 9 /*for(i=2;i <= (T - 1)*n+1;i++) 10 { 11 x = x +i - 1; 12 if(x > k)x = x%k; 13 if(i % n == 1)sum += x; 14 } 15 cout<<sum<<endl;*/ 16 for(i = 1;i < T;i++) 17 { 18 x0 = x0 + (i * n + 1)* n - n*(n + 1)/2; 19 //cout<<x0<<endl; 20 x = x0%k; 21 x0 = x; 22 sum += x; 23 } 24 printf("%I64d\n",sum); 25 return 0; 26 }
我在網上還看到了一個代碼,遞推公式和我並不同,可是提交也對了。題目中只有6個測試數據,也許並不能真正檢測。網上代碼以下:
1 #include<stdio.h> 2 int main() 3 { 4 long long n,k,t,i,total=1,op=1,cishu=1; 5 scanf("%I64d%I64d%I64d",&n,&k,&t); 6 for(i=1;i<t;i++) 7 { long long op1=((n*i+1+n*(i-1))*n/2)%k; 8 op+=op1; 9 op%=k; 10 total+=op; 11 } 12 printf("%I64d\n",total); 13 return 0; 14 }