zoukankan      html  css  js  c++  java
  • NOI2001——陨石的秘密(计数类dp)

    原题链接
    思路:
    看的是lyd老师的题解
    dp状态找的很巧妙:
    d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l]表示深度不超过 i i i,用了 j j j对花括号, k k k对中括号, l l l对小括号组成的括号序列的数量。
    这样只需要枚举四层:

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

    枚举的顺序也是要注意的,因为 S S SS SS表达式的要求。
    接下来考虑转移:
    划分依据是将括号序列分为第一部分和第二部分。
    由于两个 S S SS SS序列拼接时,深度为 m a x ( d 1 , d 2 ) max(d1,d2) max(d1,d2),所以第二部分的长度可以为 [ 1 , i ] [1,i] [1,i]中的任意数,对应到 d d d p p p数组的第一维为 i i i
    由于是求的数量,所以是乘法原理,根据第一部分最外层的不同括号进行再次枚举。
    比如当第一部分最外层为花括号时,第一部分里面可以是花括号、中括号、小括号,就要进行三层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 p p个花括号, q q q个中括号, r r r个小括号,留给第二部分的就是 j − p j-p jp个花括号, k − q k-q kq个中括号, l − r l-r lr个小括号。由于第一部分的最外层已经确定是花括号了,所以对应转移的深度范围也变成了 [ 1 , i − 1 ] [1,i-1] [1,i1],对应dp的第一维为 i − 1 i-1 i1

    代码:

    ///#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;
    }
    
    
  • 相关阅读:
    Study Plan The TwentySecond Day
    Study Plan The Nineteenth Day
    Study Plan The TwentySeventh Day
    Study Plan The Twentieth Day
    Study Plan The TwentyFirst Day
    python实现进程的三种方式及其区别
    yum makecache
    JSONPath 表达式的使用
    oracle执行cmd的实现方法
    php daodb插入、更新与删除数据
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853020.html
Copyright © 2011-2022 走看看