思路
区间dp,这个之前没写过,记一下这个题。一般形式就三个循环,从外到里枚举区间长度,区间起点,分割点。这题用f[i]
[j]记录,[i,j]是合法序列且i,j是匹配的括号的方案数,g[i]
[j]表示[i,j]是合法序列的方案数。
转移:f[i] [j]=k*g[i+1] [j-1],k为i,j上可匹配的括号数。 g[i] [j]=g[i]
[t-1]+f[t] [j]
复杂度O(n)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define ls 2*x #define rs 2*x+1 #define mid ((l+r)/2) #define pii pair<int,int> #define fi first #define se second #define int long long const int N=550; const int mod=1e9+7; const int inf=1e18; int a[N],f[N][N],g[N][N]; signed main() { int T; cin>>T; while(T--) { memset(g,0,sizeof(g)); memset(f,0,sizeof(f)); int n,m; cin>>n>>m; for(int i=1; i<=n; i++) { cin>>a[i]; } if(n%2==1) { cout<<"0\n"; continue; } for(int i=0; i<=n; i++) { g[i+1][i]=1; } for(int len=2; len<=n; len+=2) { for(int l=1; l+len-1<=n; l++) { int r=l+len-1; if(a[l]>=0&&a[r]<=0) { int e=0; if(a[l]==0&&a[r]==0)e=m; else if(a[l]==0||a[r]==0)e=1; else if(a[l]+a[r]==0)e=1; f[l][r]=g[l+1][r-1]*e%mod; } for(int t=l; t<=r; t+=2) { g[l][r]=(g[l][r]+g[l][t-1]*f[t][r])%mod; } } } cout<<g[1][n]<<endl; } return 0; }
|