*题解:P5694 [NOI2001] 陨石的秘密

原题链接

解析

有一个好想的状态是设 \(f_{l_1,l_2,l_3,d}\) 表示含有 \(l_1\){}\(l_2\)[]\(l_3\)(),深度为 \(d\) 的 SS 串个数。

对于转移,考虑从某个状态加上一对括号转移过来。问题在于可加括号的地方实在太多,并且还有括号种类的影响。所以我们需要对这两者进行限定:将一个 SS 表达式 \(S\) 分隔成 \(AB = S\),其中 \(A,B\) 也为 SS 表达式,然后加一对括号把 \(A\) 包裹起来变为 \((A)B\)\([A]B\)\(\{A\}B\),把 \(S\) 的信息转移到这些串。可以发现,每个非空 SS 串能且仅能分离出一个唯一的 \(B\) 串,这也就保证了我们的统计是不重不漏的。

在列状态转移方程之前,可以预见的是,我们在转移时需要枚举 \(A\)\(B\) 的深度。此时有一个经典技巧是将状态改写,求深度不超过 \(d\) 的 SS 串个数,求答案时再做差分。

按照改良后的状态,可以列出状态转移方程:

加小括号:

\[\large f_{l_1,l_2,l_3,d} \leftarrow f_{l_1,l_2,l_3,d} + \sum_{z = 0} ^ {l_3 - 1} f_{0,0,z,d - 1} \cdot f_{l_1,l_2,l_3 - z - 1,d} \]

加中括号:

\[\large f_{l_1,l_2,l_3,d} \leftarrow f_{l_1,l_2,l_3,d} + \sum_{y = 0} ^ {l_2 - 1}\sum_{z = 0} ^ {l_3 - 1} f_{0,y,z,d - 1} \cdot f_{l_1,l_2 - y - 1,l_3 - z,d} \]

加大括号:

\[\large f_{l_1,l_2,l_3,d} \leftarrow f_{l_1,l_2,l_3,d} + \sum_{x = 0}^{l_1 - 1}\sum_{y = 0} ^ {l_2 - 1}\sum_{z = 0} ^ {l_3 - 1} f_{x,y,z,d - 1} \cdot f_{l_1 - x - 1,l_2 - y,l_3 - z,d} \]

代码

/*
*/
#include <bits/stdc++.h>
#define mid ((1ll * l + r) >> 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 30 + 5,M = 10 + 5,L = 19,L2 = 17,mod = 11380; 
int f[M][M][M][N];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout); 
	int L1,L2,L3,d;
	cin>>L1>>L2>>L3>>d;
	if(d == 0){
		if(!L1 && !L2 && !L3){
			cout<<1;
		}else{
			cout<<0;
		}
		return 0;
	}
	int n = (L1 + L2 + L3) * 2; 
	f[0][0][0][0] = 1;
	for(int dep = 1;dep <= d;dep++){
		f[0][0][0][dep] = 1;
		for(int l3 = 0;l3 <= L3;l3++){
			for(int l2 = 0;l2 <= L2;l2++){
				for(int l1 = 0;l1 <= L1;l1++){
					for(int z = 0;z <= l3;z++){
						if(z != l3){
							f[l1][l2][l3][dep] = (f[l1][l2][l3][dep] + f[0][0][z][dep - 1] * f[l1][l2][l3 - z - 1][dep] % mod) % mod;							
						}
						for(int y = 0;y <= l2;y++){
							if(y != l2){
								f[l1][l2][l3][dep] = (f[l1][l2][l3][dep] + f[0][y][z][dep - 1] * f[l1][l2 - y - 1][l3 - z][dep] % mod) % mod;							
							}
							for(int x = 0;x < l1;x++){
								f[l1][l2][l3][dep] = (f[l1][l2][l3][dep] + f[x][y][z][dep - 1] * f[l1 - x - 1][l2 - y][l3 - z][dep] % mod) % mod;
							}
						}
					}
				}
			}
		}
	}
	cout<<(f[L1][L2][L3][d] + mod - f[L1][L2][L3][d - 1]) % mod;
	return 0;
}
posted @ 2026-05-21 18:10  yutar  阅读(8)  评论(0)    收藏  举报