(POJ1187)
真是一个有趣的题目……我真是……唉……
我相信肯定有很多人拿到这道题会设如下的状态:
(f[l1][l2][l3][d])为有(l1)个({ }),(l2)个([]),(l3)个(())时深度为(d)的个数,但是你想一下就会发现,不能转移!
因为你无法控制子状态中(d)的最大值,可怜~(@谁是鸽王)
于是就有这样一种神仙状态:(f[l1][l2][l3][d])为有(l1)个({ }),(l2)个([]),(l3)个(())时深度不超过(d)的个数!
(Woc),太妙了吧,这样我们就不用考虑最大值,只用用排列组合将子状态弄一起就行了!
具体转移:
考虑我们的当前串为两个部分,那么我们算出两个部分的答案后相乘即可,至于每个部分,我们枚举外面({ }),([]),()的个数即可,这里要注意一下循环顺序,其他的问题就不大了。
上代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int p=11380;
int L1,L2,L3,D,f[20][20][30][40];
inline int Dfs(int l1,int l2,int l3,int d)
{
int ans=0;
if(!d&&(l1|l2|l3)) return 0;
if(!(l1|l2|l3)) return f[l1][l2][l3][d]=1;
if(f[l1][l2][l3][d]) return f[l1][l2][l3][d];
for(int i=0;i<=l3;i++)
{
if(i) ans=(ans+Dfs(0,0,i-1,d-1)%p*Dfs(l1,l2,l3-i,d)%p)%p;
for(int j=0;j<=l2;j++)
{
if(j) ans=(ans+Dfs(0,j-1,i,d-1)%p*Dfs(l1,l2-j,l3-i,d)%p)%p;
for(int k=1;k<=l1;k++)
ans=(ans+Dfs(k-1,j,i,d-1)%p*Dfs(l1-k,l2-j,l3-i,d)%p)%p;
}
}
return f[l1][l2][l3][d]=ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Text1.in","r",stdin);
#endif
L1=read(),L2=read(),L3=read(),D=read();
Dfs(L1,L2,L3,D); if(D) Dfs(L1,L2,L3,D-1);
int ans=f[L1][L2][L3][D]-(D?f[L1][L2][L3][D-1]:0);
printf("%d",(ans+p)%p);
}