LXIX.[USACO18JAN]Stamp Painting G

思路:

发现任何具有一段长度大于等于\(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;
}