1. 程式人生 > >2018.10.25 洛谷P4187 [USACO18JAN]Stamp Painting(計數dp)

2018.10.25 洛谷P4187 [USACO18JAN]Stamp Painting(計數dp)

傳送門 其實本來想做組合數學的2333. 誰知道是道dpdp. 唉只能順手做了

還是用真難則反的思想。 這題我們倒著考慮,只需要求出不合法方案數就行了。 這個顯然是隨便dpdp的。 f[i]f[i]表示到第ii個格子不合法的方案數。 那麼有兩種情況。

  1. i<ki<k,則無論怎麼當前格子染都不合法,f[i]=f[i1]mf[i]=f[i-1]*m
  2. iki\geq k,則從當前的格子向左染最多染到第ik+1i-k+1個格子,因此f[i]=(m1)j=ik+1i1f[i]f[i]=(m-1)\sum _{j=i-k+1} ^{i-1}f[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; }