题意:
现在有一个长度为n的布,你有m个颜色不同的大小为k的章,你需要在这张布上盖章,可以部分区间覆盖,但是不能超过这个布的大小,问你最终这张布的颜色的情况数。
题解:
我想了两个小时还是没想出来呀,但是已经非常接近答案了,就有一块地方想错了。
那么这块布每一个单位有m种可能的颜色,但是由于章的大小为k,所以没有一块连续相同颜色的区间长度>=k的情况是不存在的,也就是说至少有一个区间的连续相同颜色长度>=k。那么我们用ans来记录已经符合的情况数,用dp记录还未符合的情况数,
我们枚举每个单位来做这道题,那么在i=k的时候,ans=m,dp[i]=dp[i-1]*m-m,也就是在k位置的时候已经有m种情况是符合要求的了,那么对于之后的情况,
a
n
s
=
(
a
n
s
∗
m
+
d
p
[
i
−
k
]
∗
(
m
−
1
)
)
%
m
o
d
ans=(ans*m+dp[i-k]*(m-1))\%mod
ans=(ans∗m+dp[i−k]∗(m−1))%mod
为什么不能数dp[i-k+1]呢?
因为dp虽然不允许连续长度为k的情况存在,但是允许更小的情况存在,也就是说当dp[i-k+1]的左边有连续相同的格子>=2的时候,我们就多加了情况数。
dp的状态转移方程:
d
p
[
i
]
=
(
d
p
[
i
−
1
]
∗
m
%
m
o
d
−
d
p
[
i
−
k
]
∗
(
m
−
1
)
%
m
o
d
+
m
o
d
)
%
m
o
d
dp[i]=(dp[i-1]*m\%mod-dp[i-k]*(m-1)\%mod+mod)\%mod
dp[i]=(dp[i−1]∗m%mod−dp[i−k]∗(m−1)%mod+mod)%mod
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
const int N=1e6+5;
ll dp[N];
int main()
{
ll n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
ll ans=0;
dp[0]=1;
for(int i=1;i<k;i++)
dp[i]=dp[i-1]*m%mod;
dp[k]=(dp[k-1]*m-m)%mod;
ans=m;
for(int i=k+1;i<=n;i++)
ans=(ans*m+dp[i-k]*(m-1))%mod,dp[i]=(dp[i-1]*m%mod-dp[i-k]*(m-1)%mod+mod)%mod;
printf("%d\n",ans);
return 0;
}