思路:
发现任何具有一段长度大于等于\(K\)的相同颜色区间的串都是合法的(这个区间被看作最后一次染色的目标)。
因此反向思考,我们求出所有不具有长度大于等于\(k\)的相同颜色区间的串数量,然后用总数量(\(M^N\))减一下即可。
我们设\(f[i]\)表示前\(i\)位的方案数。
则有
\(f[i]=\begin{cases}M^i(1\leq i<K)\\(\sum\limits_{j=i-K+1}^{i-1}f[j])(M-1)\end{cases}\)
复杂度\(O(NK)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,p,f[1001000],res=1;
int main(){
scanf("%d%d%d",&n,&m,&p);
f[0]=1;
for(int i=1;i<p;i++,res=(1ll*res*m)%mod)f[i]=(1ll*f[i-1]*m)%mod;
for(int i=p;i<=n;i++,res=(1ll*res*m)%mod){
for(int j=i-p+1;j<i;j++)(f[i]+=f[j])%=mod;
f[i]=1ll*f[i]*(m-1)%mod;
}
// for(int i=1;i<=n;i++)printf("%d ",f[i]);
printf("%d\n",(mod+res-f[n])%mod);
return 0;
}
然后套上前缀和,复杂度\(O(N)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,p,f[1001000],res=1,s[1001000];
int main(){
scanf("%d%d%d",&n,&m,&p);
f[0]=1;
for(int i=1;i<p;i++,res=(1ll*res*m)%mod)f[i]=(1ll*f[i-1]*m)%mod,s[i]=(s[i-1]+f[i])%mod;
for(int i=p;i<=n;i++,res=(1ll*res*m)%mod)f[i]=1ll*(s[i-1]-s[i-p]+mod)%mod*(m-1)%mod,s[i]=(s[i-1]+f[i])%mod;
printf("%d\n",(mod+res-f[n])%mod);
return 0;
}