前言
这是七月集训的第十六日,今日的训练内容是 队列
解题报告
1.力扣2327
原题链接
题目概述
在第 1 天,有一个人发现了一个秘密。
给你一个整数 delay ,表示每个人会在发现秘密后的 delay 天之后,每天 给一个新的人 分享 秘密。同时给你一个整数 forget ,表示每个人在发现秘密 forget 天之后会 忘记 这个秘密。一个人 不能 在忘记秘密那一天及之后的日子里分享秘密。
给你一个整数 n ,请你返回在第 n 天结束时,知道秘密的人数。由于答案可能会很大,请你将结果对 109 + 7 取余 后返回。
解题思路
这题实际上是一个动态规划的题目,接下来仔细的讲一讲本题使用动态规划的流程:
1.设计状态
首先定义一个状态数组 dp[i] ,表示第 n 天时获得了秘密的人数。今日的人会在第delay天后每日分享秘密直到第i+forget-1天为止(注意,在忘记的那一天是不会获得秘密的。
2.写出状态转移方程
根据上述的分析可以写出状态转移方程为 **d[j]+=d[i]**其中的 j 的范围是 [i+delay,i+forget-1].
3.设定初始状态
第一天的时候有一个人获得了秘密,因此 dp[1] = 1;
4.执行状态转移
见代码剖析部分
5.返回最终的解
这里要注意一下,最终所返回的解是第 n 时知道秘密的人,而不是第 n 天获得秘密的人。由于在 n-forget天及其以前的人到了第 n天的时候全都已经忘记了秘密,因此只需要统计从第 n-forget+1 天到第 n 内获得了秘密的人即可。
源码剖析
int peopleAwareOfSecret(int n, int delay, int forget){
int dp[1001]={0};
int ans = 0;
dp[1]=1;
int i,j;
for(i = 1;i<=n;++i){
for(j=i+delay;j<i+forget&&j<=n;++j){
dp[j]+=dp[i];
dp[j] = dp[j]>1000000007?dp[j]-1000000007:dp[j];
}
}
for(i = n-forget+1;i<=n;++i){
ans+=dp[i];
ans = ans>1000000007?ans-1000000007:ans;
}
return ans;
}