1. 程式人生 > >Codeforces 337C:Quiz(貪心+規律+快速冪)

Codeforces 337C:Quiz(貪心+規律+快速冪)

Note

Sample 1. Manao answered 3 questions out of 5, and his score would double for each two consecutive correct answers. If Manao had answered the first, third and fifth questions, he would have scored as much as 3 points.

Sample 2. Now Manao answered 4 questions. The minimum possible score is obtained when the only wrong answer is to the question 4.

Also note that you are asked to minimize the score and not the remainder of the score modulo 1000000009. For example, if Manao could obtain either 2000000000 or 2000000020 points, the answer is 2000000000 mod 1000000009, even though 2000000020 mod 1000000009 is a smaller number.

題目大意:有n道題,小明答對了m道,問他最少得多少分?得分規則,有一個計數器記錄連著答對題目的數字,每連著答對k道題,那麼當前分數*2,然後計數器清零,普通的+1。

解題思路:要求最少得分,那麼應該使連著答對的都堆放在前面(因為*2後小,貪心),其餘答對的都不讓連著答對放在後面即可。

現在考慮前面,第一次連著答對k道題,那麼此時得分為2k,繼續連著答對k次,得分為(2k+k)*2=6k,繼續連著答對k次,得分為(6k+k)*2=14k。。。發現規律第n次連著答對時得分為(2^(n+1)-2)*k,加上剩下的不連著答對的(m-連著答對次數*k)*1即可。

程式碼如下:

#include <cstdio>
#define MOD 1000000009
#define LL long long
LL quickpow(LL a,LL b)  
{  
    LL ans=1;  
    LL base=a;  
    while(b)  
    {  
        if(b&1)  
        {  
            ans=(ans*base)%MOD;  
        }  
        base=(base*base)%MOD;  
        b>>=1;  
    }  
    return ans;  
}  
int main()
{
	LL n,m,k;
	while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF)
	{
		LL cuo=n-m;//錯誤的題目數 
		LL kuai=n/k;//一共分成k塊考慮 
		if(kuai<=cuo)//錯誤的多餘分出的快數,說明每一塊至少得錯一道,不滿足翻倍的條件 
		{
			printf("%lld\n",m%MOD);
		}
		else
		{
			LL ci=kuai-cuo;//翻倍的次數 
			LL ans=k*(quickpow(2,ci+1)-2)%MOD;//連著答對的總分 
			ans=(ans+m-ci*k+MOD)%MOD;//+MOD防止結果為負 *****這點wa了好幾次。。。 
			printf("%lld\n",ans);
		}
	}
	return 0;
}