P5694 [NOI2001] 陨石的秘密

一道有趣的高维计数 DP。

题目大意

定义合法的括号串为:

  1. 仅由 (), [], {} 组成;
  2. 空串是合法括号串;
  3. A 是合法括号串且不含 [], {},则 (A) 是合法括号串;
  4. A 是合法括号串且不含 {},则 [A] 是合法括号串;
  5. A 是合法括号串,则 {A} 是合法括号串;
  6. A,B 均为合法括号串,则 AB 也是合法括号串。

定义一个括号串的深度为最大的括号嵌套数,求使用了 L1,L2,L3{}, [], () 且深度为 D 的合法括号串数量,答案对 11380 取模。

大体思路

由于 L1L3,D 均不大,直接使用高维 DP,状态定义照抄题面。故定义 F(d,i,j,k) 表示使用了 i,j,k 对大、中、小括号且深度为 d 的数量。

状态转移自然是将当前串分割成两个串 TS,使得 S 的深度为 d,用某一种括号去套一个合法的串 T。由于嵌套一层后深度 d,要求这个合法串 T 的深度不大于 d1

这时,我们发现需要枚举所有 d1 的深度,太过麻烦,因此对 F 做前缀和处理,即将状态定义改为 F(d,i,j,k) 表示使用了 i,j,k 对大、中、小括号且深度 d 的数量。

对当前串 TS,可以通过一个括号嵌套变成 (T)S[T]S{T}S。我们可以通过枚举 T 中包含多少 {}, [], (),得到状态转移方程:

F(d,i,j,k)=a=0i1b=0jc=0kF(d1,a,b,c)×F(d,i1a,jb,kc)+b=0j1c=0kF(d1,0,b,c)×F(d,i,j1b,kc)+c=0k1F(d1,0,0,c)×F(d,i,j,k1c)

特殊地,对于 i=j=k=0 时,F(d,0,0,0)=1

输出时,通过前缀和做差即可,需要特判 D=0 以及 L1=L2=L3=0 的情况。时间复杂度 O(DL6)

完整代码

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re int ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair<int, int> PII;
const ll mod = 11380;
namespace IO_ReadWrite {
#define re register
#define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++)
char _buf[1<<21], *p1 = _buf, *p2 = _buf;
template <typename T>
inline void read(T &x){
x = 0; re T f=1; re char c = gg;
while(c > 57 || c < 48){if(c == '-') f = -1;c = gg;}
while(c >= 48 &&c <= 57){x = (x<<1) + (x<<3) + (c^48);c = gg;}
x *= f;return;
}
inline void ReadChar(char &c){
c = gg;
while(!isalpha(c)) c = gg;
}
template <typename T>
inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x/10);
putchar('0' + x % 10);
}
template <typename T>
inline void writeln(T x){write(x); putchar('\n');}
}
using namespace IO_ReadWrite;
ll L1, L2, L3, D, f[35][12][12][12];
int main () {
read(L1); read(L2); read(L3); read(D);
f[0][0][0][0] = 1;
rep(d, 1, D) {
f[d][0][0][0] = 1;
rep(i, 0, L1) rep(j, 0, L2) rep(k, 0, L3) {
if(!i && !j && !k) continue;
rep(a, 0, i - 1) rep(b, 0, j) rep(c, 0, k)
(f[d][i][j][k] += f[d - 1][a][b][c] * f[d][i-1 - a][j - b][k - c]) %= mod;
rep(b, 0, j - 1) rep(c, 0, k)
(f[d][i][j][k] += f[d - 1][0][b][c] * f[d][i][j-1 - b][k - c]) %= mod;
rep(c, 0, k - 1)
(f[d][i][j][k] += f[d - 1][0][0][c] * f[d][i][j][k-1 - c]) %= mod;
}
}
if(!D) writeln(((!L1 && !L2 && !L3) ? 1 : 0));
else if(!L1 && !L2 && !L3) writeln(0);
else writeln((f[D][L1][L2][L3] - f[D - 1][L1][L2][L3] + mod) % mod);
return 0;
}
posted @   Mars_Dingdang  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示