[HNOI2010]合唱隊
阿新 • • 發佈:2018-11-01
題目
https://www.luogu.org/problemnew/show/P3205
思路
定義f[l,r]表示在最終序列區間序列[l,r]中,最後一個新增的人是l時所得到的方案數,g[l,r]表示在最終序列區間序列[l,r]中,最後一個新增的人是r時所得到的方案數。[l,r]這個區間可以從[l+1,r]和[l,r-1]轉移過來,判斷最後這個人和上一個人的大小關係,分成兩類:除去最後這個人,上一個人新增在區間左邊/右邊。
得到動態轉移方程:f[l,r]:=f[l+1,r] * (a[l]<a[l+1])+g[l+1,r] * (a[l]<a[r]);
g[l,r]:=f[l,r-1] * (a[l]<a[r])+g[l,r-1] * (a[r-1]<a[r]);
程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1010,mod=19650827; int n,A[maxn],f[maxn][maxn][2]; int dfs(int l,int r,int op) { if(l==r) f[l][r][op]=((A[l]<A[l+1]&&op)|(A[l]>A[l-1]&&!op))?1:0; if(f[l][r][op]!=-1) return f[l][r][op]; int ans=0; if(op==1) { if(A[l]<A[r+1]) ans+=dfs(l+1,r,0); if(A[r]<A[r+1]) ans+=dfs(l,r-1,1); } else { if(A[l]>A[l-1]) ans+=dfs(l+1,r,0); if(A[r]>A[l-1]) ans+=dfs(l,r-1,1); } return f[l][r][op]=ans%mod; } int main() { scanf("%d",&n);memset(f,-1,sizeof(f)); for(int i=1; i<=n; i++) scanf("%d",&A[i]); printf("%d\n",dfs(1,n,0)); return 0; }