题目大意:Manao 在进行测试,一共要回答n个题目,答对一题得一分,如果连续答对k到题,那么他得到的分数加倍。答错一题或者是加倍后,连续答对题目的个数清零重新开 始计数。现在给定n和k,还有m(Manao一共答对的题目数),求最少Manao可以得多分。
题目分析:首先讨论能否加倍。
假设,全部能加倍,那么一共会加倍(n/k)次,那么如果全部不能加倍,需要答错(n/k)到题目
所以可以根据(n-m)和(n/k)的大小,来判断Manao的分数能否加倍。
1)n/k < n-m(不能加倍)那么此时,Manao最少只能得分m
2)n/k >= n-m (能加倍)如果能加倍,n一共会被分为三个部分(这种分发保证得分最少)
第一个部分 连续答对X到题目(有加倍)如果有加倍,当然趁得分少的时候加倍了
第二个部分 没有加倍,且没连续k道题目,那么第k到题目答错 这是最优的一种排法
第三个部分 最后连续答对题目,但是没有加倍 答错的题目排在前面,也是最优的,因为答错的题目要破坏加倍
将n分为每份大小为k的区域(n/k),那么还剩下(n%k)(这n%k不会加倍)
那么如果有加倍,只能在这(n/k)个区域的最前面开始加倍,然后后面的每个区域的最后一个总是答错(这里有(n-m)个答错的题,所以这些区域得分为(n-m)*(k-1)),那么连续加倍((m-(n-m)*(k-1))/ k)次。
下面是代码:
#include <stdio.h>
#define mod 1000000009
int pow_mod(long long a,long long n,long long m)
{
long long ret = 1;
while(n)
{
if(n&1) ret = ret*a%m;
a = (a*a)%m;
n >>= 1;
}
return (int)ret%m;
}
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int s1 = n/k;
int s2 = n-m;
if(s1-s2 < 0) printf("%d\n",m);
else
{
int exp = s1 - s2;
long long ans = 0;
ans = pow_mod(2,exp+1,mod) - 2;
ans = (ans*k + mod)%mod;
ans = (ans + (long long) s2 * (k-1) + n%k) % mod;
printf("%I64d\n",ans);
}
return 0;
}