NOI2001——陨石的秘密(计数类dp)

简介: NOI2001——陨石的秘密(计数类dp)

原题链接

思路:

看的是lyd老师的题解

dp状态找的很巧妙:

d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l]dp[i][j][k][l]表示深度不超过i ii,用了j jj对花括号,k kk对中括号,l ll对小括号组成的括号序列的数量。

这样只需要枚举四层:

枚举深度
  枚举花括号的个数
    枚举中括号的个数
      枚举小括号的个数

枚举的顺序也是要注意的,因为S S SSSS表达式的要求。

接下来考虑转移:

划分依据是将括号序列分为第一部分和第二部分。

由于两个S S SSSS序列拼接时,深度为m a x ( d 1 , d 2 ) max(d1,d2)max(d1,d2),所以第二部分的长度可以为[ 1 , i ] [1,i][1,i]中的任意数,对应到d ddp pp数组的第一维为i ii。

由于是求的数量,所以是乘法原理,根据第一部分最外层的不同括号进行再次枚举。

比如当第一部分最外层为花括号时,第一部分里面可以是花括号、中括号、小括号,就要进行三层for枚举。

for(int p=1;p<=j;p++)
                for(int q=0;q<=k;q++)
                  for(int r=0;r<=l;r++)
                    dp[i][j][k][l]=(dp[i][j][k][l]+dp[i-1][p-1][q][r]*dp[i][j-p][k-q][l-r])%mod;

假设第一部分花费了p pp个花括号,q qq个中括号,r rr个小括号,留给第二部分的就是j − p j-pj−p个花括号,k − q k-qk−q个中括号,l − r l-rl−r个小括号。由于第一部分的最外层已经确定是花括号了,所以对应转移的深度范围也变成了[ 1 , i − 1 ] [1,i-1][1,i−1],对应dp的第一维为i − 1 i-1i−1。


代码:

///#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b, ll p)
{
    ll res = 1;
    while(b)
    {
        if(b & 1)res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
const int inf = 0x3f3f3f3f;
#define PI acos(-1)
const double eps = 1e-8;
const int maxn = 2e5 + 7,mod=11380;
int dp[31][11][11][11],l1,l2,l3,l4,d;
int main()
{
    l1=read,l2=read,l3=read,d=read;
    for(int i=0;i<=d;i++) dp[i][0][0][0]=1;
    for(int i=1;i<=d;i++)///枚举深度
      for(int j=0;j<=l1;j++)
        for(int k=0;k<=l2;k++)
          for(int l=0;l<=l3;l++){
            if(j>0){///第一层最外层是{}
              for(int p=1;p<=j;p++)
                for(int q=0;q<=k;q++)
                  for(int r=0;r<=l;r++)
                    dp[i][j][k][l]=(dp[i][j][k][l]+dp[i-1][p-1][q][r]*dp[i][j-p][k-q][l-r])%mod;
            }
            if(k>0){///第一层最外面是[]
              for(int q=1;q<=k;q++)
                for(int r=0;r<=l;r++)
                  dp[i][j][k][l]=(dp[i][j][k][l]+dp[i-1][0][q-1][r]*dp[i][j][k-q][l-r])%mod;
            }
            if(l>0){
              for(int r=1;r<=l;r++)
                dp[i][j][k][l]=(dp[i][j][k][l]+dp[i-1][0][0][r-1]*dp[i][j][k][l-r])%mod;
            }
          }
    int tmp=dp[d][l1][l2][l3];
    if(d) tmp-=dp[d-1][l1][l2][l3];
    if(tmp<0) tmp=(tmp+mod)%mod;
    cout<<tmp;
    return 0;
}
目录
相关文章
|
4月前
【每日一题Day357】LC1155掷骰子等于目标和的方法数 | dp
【每日一题Day357】LC1155掷骰子等于目标和的方法数 | dp
50 0
|
定位技术
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
170 0
|
4月前
|
算法 Python Java
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
38 0
Java每日一练(20230414) Pow(x, n) 、旋转图像、买卖股票的最佳时机 IV
|
4月前
【每日一题Day353】LC2525根据规则将箱子分类 | 模拟
【每日一题Day353】LC2525根据规则将箱子分类 | 模拟
26 0
|
4月前
|
C++
[C++/PTA] 2017Final进位与借位
[C++/PTA] 2017Final进位与借位
156 0
|
10月前
|
人工智能
【DP练习】月饼盒(提高版)(vijos1255)
【DP练习】月饼盒(提高版)(vijos1255)
46 0
初学算法之递归---放苹果
初学算法之递归---放苹果
|
定位技术
(枚举)(模拟)(二位前缀和)99. 激光炸弹
(枚举)(模拟)(二位前缀和)99. 激光炸弹
74 0
|
机器学习/深度学习
UPC 换位置游戏(BFS || 并查集判环)
UPC 换位置游戏(BFS || 并查集判环)
97 0
UPC 换位置游戏(BFS || 并查集判环)