Problem
用
M
M
M 种长为
K
K
K 的印章(每种颜色均不同),给长为
N
N
N 的纸条盖章。
问最后会得到多少种不同的状态。
Solution
反过来想,答案就是总数减去不合法情况。
总数也就是每个块随便选颜色,即
m
n
m^n
mn
而每个印章长度为
K
K
K ,因此如果最长的一段相同颜色的长度小于
K
K
K ,那么就说明此情况不合法。
那么我们现在的认为就是求不合法的情况。
定义
f
[
i
]
f[i]
f[i] 表示到
i
i
i 位置不合法的情况。
f
[
i
]
=
∑
f
[
j
]
∗
(
m
−
1
)
i
−
k
+
1
<
=
j
<
i
f[i]=\sum f[j]*(m-1)\quad i-k+1<=j<i
f[i]=∑f[j]∗(m−1)i−k+1<=j<i
(表示从
j
+
1
j+1
j+1 到
i
i
i 设置成与
j
j
j 位置颜色不同的一种颜色,此时由定义前
j
j
j 个中是没有大于等于
k
k
k 个连续的颜色相同的,且
j
+
1
j+1
j+1 到
i
i
i 长度小于
k
k
k )
维护个前缀和就好啦。
Code
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 1000010
#define mod 1000000007
#define ll long long
int n,m,k;
ll f[N],sum[N];
inline ll pow(ll x,int y){
ll t=1;
while(y){
if(y&1) t=t*x%mod;
x=x*x%mod;y>>=1;
}return t;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
f[0]=1;sum[0]=1;
for(int i=1;i<k;i++) f[i]=f[i-1]*m%mod,sum[i]=(sum[i-1]+f[i])%mod;
for(int i=k;i<=n;i++){
f[i]=(sum[i-1]-sum[i-k])%mod*(m-1)%mod;
sum[i]=sum[i-1]+f[i];
}
printf("%lld\n",(pow(m,n)-f[n]+mod)%mod);
return 0;
}