Skip to content

Latest commit

 

History

History

2327.Number-of-People-Aware-of-a-Secret

2327.Number-of-People-Aware-of-a-Secret

解法1:N^2 DP

本题显然是一个DP,那么如何设计状态变量呢?如果dp[i]表示第i天的时候有多少人被感染,那么情况就比较复杂,因为有些人是刚被感染的(是被第i-delay天刚被感染的人传染的),有些人是已经感染了一段时间的,这两部分如何区分?此外,还要考虑到第i天可能有一部分人刚好恢复健康,那部分人对应的是第i-forget天刚被感染的人。

所以由上面的分析,在每一天中,“刚被感染”的人数是一个非常有用的信息量。所以我们应该将其单独定义。所以不妨令dp[i]表示第i天刚被感染的人。那么根据题意,在第i+delay直至i+forget-1天,每天新感染的人数都会固定增加dp[i],即

for (int j=i+delay; j<i+forget; j++)
  dp[j] += dp[i]

初始条件显然是dp[1]=1,所以似乎我们就把整个dp完整地推导了出来。

那么这个dp对答案有什么用呢?答案是求第n天的时候有多少人被感染(包括新感染和已经感染一段时间的)。事实上,我们只需要考察每天新感染的人(即dp[i])是否能坚持到第n天即可。即如果i+forget>n,那么dp[i]就可以贡献给ret。

解法2: 差分数组

从上面的dp转移方程可以看出,在一个区间内赋值同一个值,用for循环显然是低效率的,我们必然会引入差分数组。定义diff[i]表示dp[i]相比于dp[i-1]之间的增量,即dp[i]=dp[i-1]+diff[i]。于是我们可以用两处增量的定义,来替换整个for循环

diff[i+delay] += dp[i];
diff[i+forget] -= dp[i];

这里需要特别注意diff的初始条件。将解法1里dp[1]=1翻译过来,所对应的diff的初始条件是diff[1]+=1, diff[2]+=-1.