問題描述
棟棟正在和同學們玩一個數字游戲。
游戲的規則是這樣的:棟棟和同學們一共n個人圍坐在一圈。棟棟首先說出數字1。接下來,坐在棟棟左手邊的同學要說下一個數字2。再下面的一個同學要從上一個同學說的數字往下數兩個數說出來,也就是說4。下一個同學要往下數三個數,說7。依次類推。
為了使數字不至於太大,棟棟和同學們約定,當在心中數到 k-1 時,下一個數字從0開始數。例如,當k=13時,棟棟和同學們報出的前幾個數依次為: 1, 2, 4, 7, 11, 3, 9, 3, 11, 7。
游戲進行了一會兒,棟棟想知道,到目前為止,他所有說出的數字的總和是多少。
游戲的規則是這樣的:棟棟和同學們一共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;
我的答案:
#include<iostream> using namespace std; int main(){ int n,k,t; cin>>n>>k>>t; int figure=1,sum=0; for(int i=0;i<t*n;i++){ figure=(figure+i)%k; if(i%n==0){ sum+=figure; } } cout<<sum; return 0; }
但是運行至第五個測試數據時,顯示運行超時。(而且應該將int型的n,k,i 改為long long型 )
因此,需要找到更優化的算法。
以下兩個程序來自CSDN社區。
第一種:
http://blog.csdn.net/ohpyoo/article/details/44427859
代碼:
#include<stdio.h> int main(void){ int i,n,k,t; long long sum=1,a=1,cnt=1; scanf("%d%d%d",&n,&k,&t); for(i=0;i<t-1;i++){ cnt=((a+a+n-1)*n/2+cnt)%k; //下一個數字 sum+=cnt; a=a+n; //下一次的起始變量 } printf("%I64d\n",sum); return 0; }
思路:我們其實只需要知道東東的數字就好,而對他朋友的數字,我們並不關心,東東的數字從1開始,報出T個數字,那么就是游戲進行了T-1圈,而每次東東報出數字,距他下一次報數中間間隔n次,而報的數字又是每次加1,那么這是一個等差數列,我們可以算出每兩個數之間間隔多少,然后加上上一次報的數對於k求余就是這次得數,然后累加到sum中,但是由於循環次數過大,考慮溢出問題,把有溢出危險的變量聲明的大一點
第二種:
http://blog.csdn.net/qq_30076791/article/details/50578701
代碼:
#include<stdio.h> int main() { long long n,k,t; while(~scanf("%lld%lld%lld",&n,&k,&t)) { long long x=1,ans=1; long long l=1,r=n; for(int i=1; i<t; i++) { x+=(l+r)*n/2; x=x%k; ans+=x; l=1+i*n; r=n+i*n; } printf("%lld\n",ans); } return 0; }
思路與第一種相同。
