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;
    }
    
    
  • 相关阅读:
    iphone中button按钮显示为圆形解决
    获得URL含有中文出现乱码解决
    shell脚本检测监控mysql的CPU占用率
    centos6.x硬件信息统计脚本
    Linux下模拟多线程的并发并发shell脚本
    CentOS目录结构超详细版
    Centos 下搭建FTP上传下载服务器
    CentOS下输入输出重定向
    Centos时间查看修改命令date详解
    Shell脚本之awk详解
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853020.html
Copyright © 2011-2022 走看看