【题解】CF474D Flowers
题目:CF474D Flowers
DP?递推?
首先可以很快看出这是一道 DP 的题目,但与其说是 DP,还不如说是递推。
大家还记得刚学递推时教练肯定讲过的一道经典例题吗?就是爬楼梯,一个有 \(n\) 阶的楼梯,一个人爬上去,每次可以爬一阶也可以爬两阶,问有多少种爬法?其实这道题也是一样的,只不过把 \(2\) 换成了 \(k\) 而已。
于是我们开始分析,定义 \(dp[i]\) 为吃 \(i\) 个蛋糕的吃法总数。
很容易看出,如果 \(i<k\),就不可以一口气吃掉,只能一个一个吃,方法为 \(1\) 种。
如果 \(i==k\),就既可以一个一个吃掉,也可以一口气全部吃完,方法为 \(2\) 种。
如果 \(i>k\),就有两种吃法,既可以先吃 \(i-1\) 个,然后再吃一个,也可以先吃 \(i-k\) 个,再吃 \(k\) 个。方法为 \(dp[i-1]+dp[i-k]\) 种。
最后记得要开 long long,而且要一边加一边模 \(1000000007\)。
核心代码:
if(dp[i])continue;
if(i<k)
dp[i]=1;
else if(i==k)
dp[i]=2;
else
dp[i]=(dp[i-1]+dp[i-k])%1000000007;
sum[i]=(sum[i-1]+dp[i])%1000000007;
因为一组数据只有一个 \(k\),但是有很多组关于这个 \(k\) 的测试点,所以可以用一个前缀和数组统计 \(dp_1\sim dp_i\) 的和,然后根据题目中 \(mod\ 1000000007\)。
玄学优化
其实这个优化也不难想到。既然一组数据中只会有一个 \(k\),那么说明不管怎么算,\(dp[i]\) 的值算出来都是相等的。那么可以判断一下当前出现的最大 \(x_2\),如果一组输入的 \(x_2\) 值小于最大值,就说明 \(dp[x_2]\) 已经计算过,直接输出即可。
\(Code\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,k,x1,x2,Max=1;
ll dp[100005],sum[100005];
int main(){
scanf("%d %d",&t,&k);
while(t--){
scanf("%d %d",&x1,&x2);
if(Max>=x2){ //优化:判断x2和max(x2)的大小
printf("%lld\n",(sum[x2]-sum[x1-1])%1000000007);
continue;//直接跳过
}
for(int i=Max;i<=x2;i++){//只计算没计算过的
if(dp[i])continue;
if(i<k)
dp[i]=1;
else if(i==k)
dp[i]=2;
else
dp[i]=(dp[i-1]+dp[i-k])%1000000007;
sum[i]=(sum[i-1]+dp[i])%1000000007;
}
printf("%lld\n",(sum[x2]-sum[x1-1])%1000000007);
Max=x2;//更新Max的值
}
return 0;
}
究竟是什么地方错了?
然后你交上去发现WA了!
这也就是一个本蒟蒻在做题时犯的错误。
一般要取余的题都是一边计算一边取模,所以可能会造成dp数组中前面的值大于后面的值的情况。在最终计算 \(x_1\sim x_2\) 的时候做的减法运算可能是负数,负数取模就出事了。
那如何解决呢?其实很简单,只需要在取模之前再加上一个 \(1000000007\) 就可以了。
\(Code\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,k,x1,x2,Max=1;
ll dp[100005],sum[100005];
int main(){
scanf("%d %d",&t,&k);
while(t--){
scanf("%d %d",&x1,&x2);
if(Max>=x2){
printf("%lld\n",(sum[x2]-sum[x1-1]+1000000007)%1000000007);
continue;
}
for(int i=Max;i<=x2;i++){
if(dp[i])continue;
if(i<k)
dp[i]=1;
else if(i==k)
dp[i]=2;
else
dp[i]=(dp[i-1]+dp[i-k])%1000000007;
sum[i]=(sum[i-1]+dp[i])%1000000007;
}
printf("%lld\n",(sum[x2]-sum[x1-1]+1000000007)%1000000007);
Max=x2;
}
return 0;
}
终于A了!www