传送门
其实本来想做组合数学的2333.
谁知道是道dpdpdp.唉只能顺手做了
还是用真难则反的思想。
这题我们倒着考虑,只需要求出不合法方案数就行了。
这个显然是随便dpdpdp的。
f[i]f[i]f[i]表示到第iii个格子不合法的方案数。
那么有两种情况。
- i<ki<ki<k,则无论怎么当前格子染都不合法,f[i]=f[i−1]∗mf[i]=f[i-1]*mf[i]=f[i−1]∗m
- i≥ki\geq ki≥k,则从当前的格子向左染最多染到第i−k+1i-k+1i−k+1个格子,因此f[i]=(m−1)∑j=i−k+1i−1f[i]f[i]=(m-1)\sum _{j=i-k+1} ^{i-1}f[i]f[i]=(m−1)∑j=i−k+1i−1f[i]
维护一个动态的前缀和来转移就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
typedef long long ll;
const int N=1e6+5,mod=1e9+7;
int n,m,k,f[N];
int main(){
n=read(),m=read(),k=read();
f[0]=1;
int sum=0,ans=1;
for(int i=1;i<=n;++i)ans=1ll*ans*m%mod;
for(int i=1;i<=n;++i){
if(i<k)f[i]=1ll*f[i-1]*m%mod;
else f[i]=1ll*sum*(m-1)%mod;
sum+=f[i];
if(sum>=mod)sum-=mod;
if(i>=k){
sum-=f[i-k+1];
if(sum<0)sum+=mod;
}
}
ans-=f[n];
if(ans<0)ans+=mod;
cout<<ans;
return 0;
}