zoukankan      html  css  js  c++  java
  • 2019HDU多校第一场1001 BLANK (DP)(HDU6578)

    2019HDU多校第一场1001 BLANK (DP)

    题意:构造一个长度为n(n<=10)的序列,其中的值域为{0,1,2,3}存在m个限制条件,表示为 l r x意义为[L,R]区间里最多能有x个不同的数字,计算序列构造方案数

    思路

    1.首先考虑最暴力的做法,直接dfs暴力构造,碰到区间的右端点就开始判断当前构造是否满足,如果不满足就回溯,很显然,复杂度爆炸O(4^n)
    2.考虑怎么优化暴力算法,从(n<=100)不难猜出这是一个dp,考虑这种字符串构造形式的dp,肯定是一位一位有序构造,所以dp肯定是有序地扫一遍,所以进入了如何定义状态的阶段,我们注意到,一个区间里面数的种类的不同,只与当前点分别和最近的{0,1,2,3}的距离有关,如果在限制区间里面则种类+1,反之亦然。所以我们不难想到可以定义出状态dp[i][j][k][t][pos],表示{0,1,2,3}在Pos位置之前离pos最近分别在i,j,k,t,这样我们得出状态转移方程有(分别为填0,1,2,3)
    dp[i][j][k][pos][pos]+=dp[i][j][k][t][pos-1]
    dp[i][pos][k][t][pos]+=dp[i][j][k][t][pos-1]
    dp[i][pos][k][t][pos]+=dp[i][j][k][t][pos-1]
    dp[pos][j][k][t][pos]+=dp[i][j][k][t][pos-1]
    我们可以得出,时间复杂度(O(n^5))空间复杂度(O(n^5))两者都不行,所以我们需要考虑如何优化,从状态转移方程中我们可以看到在5维中总有一对pos是相同的,所以这一维可以不用占时间复杂度和空间复杂度,并且可以用数组滚动,所以空间复杂度可以为(O(n^3)),时间复杂度为(O(n^4))至此,已经满足题意了

    但是我们试图对以上状态转移进行优化时,我们会发现pos到底和哪一位一样?这很难处理。因为pos既代表了一位数的位数又代表了当前位置,这样如何表达呢?我们思考一下,pos相对于i,j,k有什么性质?pos每次都是最大的,同时填{0,1,2,3}我们并不关心他的具体取值,只关系他的分布,所以取什么值都是对称的,例如0,1,2,3如果满足条件,那么3,2,1,0也一定满足条件,所以我们可不可以仅从分布位置的大小关系入手?设置i<j<k<t那么转移就变成了
    dp[i][j][pos][now]+=dp[i][j][k][pre]
    dp[i][k][pos-1][now]+=dp[i][j][k][pre]
    dp[j][k][pos-1][now]+=dp[i][j][k][pre]
    dp[i][j][pos-1][now]+=dp[i][j][k][pre]

    我们分别解释第一个状态和第二个状态。首先我们可以知道,上一个状态最大的肯定是pos-1也就是当前状态的k=pos-1因为当前位置是pos,第一个状态表示把pos位置填上和k相同的值。而第二个状态表示把pos填上和j相同的值,那么上一个k可以就是pos-1变成了次大值,最大值变成了pos也就是当前填的值。(每个状态里面都隐藏了当前的最大t一定是位置,以此好理解转移)

    这样我们就还剩下了限制条件,我们只要把每个限制条件放进以右端点值为key的数组中,每次dp完一个位置后,看满不满足限制条件,不满足就置为0即可,因为状态的良好定义,使得判断极为简单

    思考

    碰到构造计数类dp的时候,通常是从左到右dp,我们首先考虑如何判断限制条件,再以此设计状态,状态的定义要可以很方便得判断出是否满足限制条件,对于不满足限制条件的状态,我们可以在dp中使dp数组置0来阻止其继续递推。设计状态的时候从最暴力逐渐优化,思路不能乱,不能乱了方寸,否则dp的难度一高,状态一复杂,就会导致心态爆炸,代码写炸。

    Reference

    https://blog.csdn.net/Ratina/article/details/97237438 顺便%一下这位大佬

    #include<bits/stdc++.h>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define pb push_back
    #define F first
    #define S second
    #define mkp make_pair
    const int mod=998244353;
    const int maxn=100+4;
    int dp[maxn][maxn][maxn][2];
    vector< pair<pair<int,int>,int>   >v[maxn];
    int t,n,m;
    int ans=0;
    int add(int x,int y){
        return (1ll*x+y)%mod;
    }
    int main(){
        scanf("%d",&t);
        while(t--){
            ans=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            v[i].clear();
            for(int i=0;i<m;i++){
                int l,r,x;
                scanf("%d%d%d",&l,&r,&x);
                v[r].pb(mkp(mkp(l,r),x));
            }
            
                for(int k=0;k<n;k++)
                    for(int j=0;j<max(1,k);j++)
                        for(int i=0;i<max(1,j);i++)dp[i][j][k][1]=dp[i][j][k][0]=0;
            dp[0][0][0][0]=1;
    
            
            int now=1;
            for(int pos=1;pos<=n;pos++){
                for(int k=0;k<max(pos-1,1);k++){
                    for(int j=0;j<max(1,k);j++){
                        for(int i=0;i<max(1,j);i++){
                            dp[i][j][k][now]=add(dp[i][j][k][now],dp[i][j][k][now^1]);
                            dp[i][j][pos-1][now]=add(dp[i][j][pos-1][now],dp[i][j][k][now^1]);
                            dp[j][k][pos-1][now]=add(dp[j][k][pos-1][now],dp[i][j][k][now^1]);
                            dp[i][k][pos-1][now]=add(dp[i][k][pos-1][now],dp[i][j][k][now^1]);
                            dp[i][j][k][now^1]=0;
                        
                        }
                    }
                }
                for(int k=0;k<max(pos,1);k++){
                    for(int j=0;j<max(1,k);j++){
                        for(int i=0;i<max(1,j);i++){
                            for(auto&p:v[pos]){
                                if((i>=p.F.F)+(j>=p.F.F)+(k>=p.F.F)+1!=p.S){
                                    dp[i][j][k][now]=0;
                                }
                            }
                        
                        }
                    }
                }
                now^=1;
            }
            for(int k=0;k<max(1,n);k++){
                for(int j=0;j<max(1,k);j++){
                    for(int i=0;i<max(1,j);i++){
                        ans=add(ans,dp[i][j][k][now^1]);
                    }
                }
            }
            printf("%d
    ",ans);
        
        }
    
    
        return 0;
    }
    
  • 相关阅读:
    201521123038 《Java程序设计》 第五周学习总结
    201521123020 《Java程序设计》第4周学习总结
    201521123020 《Java程序设计》第3周学习总结
    201521123020《Java程序设计》第2周学习总结
    Java第十二周学习总结
    Java第十一周学习总结
    Java第十周学习总结
    Java第九周学习总结
    Java第八周学习总结
    Java第七周学习总结
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/11247633.html
Copyright © 2011-2022 走看看