无敌水题,实际上样例解释就暴露了它递推的本质。
f[ i ]表示吃 i 个蛋糕的方案数。
那么,f[ i ]=f[ i-1 ]+f[ i-k ]; ( i >k )
这个递推和走楼梯很像。即当前i个蛋糕,可以分为两种情况:吃掉一个蛋糕,剩下蛋糕的方案数即为f[ i-1 ];或者选择吃掉k个蛋糕,剩下蛋糕的方案数为f[ i-k ]。
初始化:i < k: f[ i ]=1;
i==k:f[ i ]=2;
显然。
处理完之后再对数组求个前缀和,查询时输出即可。
值得(我)注意的是,减法取模x:A=ax+y( 全是整数 ) ,B=a’x+y’ ( a > a’,y < y’ ),A-B=( a-a’ )x+y-y’,因为 y-y’<0 ,所以自动地,A-B=(a-a’-1)x+x+y-y’ ,再取模:(A-B)%x=x+y-y’; 而我以前没接触过这个套路,对于已取模的A=y,B=y’,A-B=y-y’,然后就,GG啦!
正确操作:( A-B+x)%x。这种失误错过一次应该就会了解。
int main()
{
x=10000000;y=0;
read(t);read(k);
for(int i=1;i<=t;++i)
{
read(a[i].x);read(a[i].y);
x=min(x,a[i].x);y=max(y,a[i].y);
}//先存是因为想先确定查询上下界求前缀,其实不太有必要,耗时空可能更多。
work_();
out_();
return 0;
}
void work_()
{
memset(f,0,sizeof(f));
for(int i=1;i<k;++i) f[i]=1LL;
f[0]=0LL;f[k]=2LL;//初始化。
for(int i=k+1;i<=y;++i) f[i]=1LL*(f[i-1]+f[i-k])%1000000007;
for(int i=x;i<=y;++i)
f[i]=(f[i]+f[i-1])%1000000007;
}
void out_()
{
for(int i=1;i<=t;++i)
{
printf("%lld\n",(f[a[i].y]+1000000007-f[a[i].x-1])%1000000007);
}
}
函数顺序是为了方便看。