zoukankan      html  css  js  c++  java
  • [Codeforces 28D] Do not fear,DravDe is kind

    Brief Intro:

    对于四元组(v,c,l,r),求其子序列中v最大的和,并使其满足:

    1、Ci+Li+Ri相同

    2、L1=0,Rn=0

    3、Li=Sigma(C1...Ci-1)

    Solution:

    算是有条件约束的DP吧

    设dp[k]为选到k且选k的最大值

    对于每个条件,我们这样处理:

    1、将所有数据按Ci+Li+Ri的和进行分组处理

    2、当Li=0时,将其视为起点;当Ri=0时,用dp[i]去更新res

    3、此条件可转换为:仅当Lp=Lq+Cq时,dp[p]可由dp[q]转移而来

    于是我们将数组按SUM排序后,用Best_val[t]记录Lk+Ck=t时最大的dp[k],用Best_id[t]记录Lk+Ck=t时最大的k,这样每次dp[k]由Best_val[Lk]更新,再由Best_id[Lk]更新父亲节点即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        char ch;int num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    template<class T> inline void putnum(T x)
    {
        if(x<0)putchar('-'),x=-x;
        register short a[20]={},sz=0;
        while(x)a[sz++]=x%10,x/=10;
        if(sz==0)putchar('0');
        for(int i=sz-1;i>=0;i--)putchar('0'+a[i]);
        putchar(' ');
    }
    
    const int MAXN=1e5+10;
    int n;
    struct truck
    {
        int v,c,l,r,num;
    }dat[MAXN];
    int pre[MAXN],dp[MAXN],b_val[MAXN],b_id[MAXN],T[MAXN],start=-1,res=0;
    
    bool cmp(truck x,truck y)
    {
        if(x.c+x.l+x.r==y.c+y.l+y.r) return x.num<y.num;
        return x.c+x.l+x.r<y.c+y.l+y.r;
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
            dat[i].v=read(),dat[i].c=read(),dat[i].l=read(),dat[i].r=read(),dat[i].num=i;
        
        sort(dat+1,dat+n+1,cmp);
        
        for(int i=1,j=1;i<=n;i=j)
        {
            while(j<=n && dat[i].c+dat[i].l+dat[i].r==dat[j].c+dat[j].l+dat[j].r) j++;
            for(int k=i;k<j;k++)
            {
                if(!dat[k].l) dp[k]=dat[k].v,pre[k]=-1;
                else if(T[dat[k].l]==i)
                {
                    dp[k]=b_val[dat[k].l]+dat[k].v;
                    pre[k]=b_id[dat[k].l];
                }
                
                int t=dat[k].l+dat[k].c;
                if(T[t]!=i || dp[k]>b_val[t])
                {
                    b_val[t]=dp[k];T[t]=i;b_id[t]=k;
                }
                
                if(!dat[k].r && dp[k]>res) res=dp[k],start=k;
            }
        }
        
        vector<int> res;
        while(start!=-1) res.push_back(dat[start].num),start=pre[start];
        putnum(res.size());puts("");
        
        if(!res.size()) return 0;
        for(int i=res.size()-1;i>=0;i--) putnum(res[i]);
        return 0;
    }

    Review:

    1、 注意子序列是不能改变相对次序的,因此排序时在SUM相同时要按原ID作为关键字排序(保证稳定性)

    2、 对vector.size()少进行减法运算,防止unsigned int溢出

    3、 对于具有决策单调性的DP,只要记录当前转移态前最优的状态即可

  • 相关阅读:
    搞笑的口误 [调剂一下生活 :D]
    Win 2003远程管理的实现
    asp.net 实现购物车(DataSet)详细代码[转]
    SQL Server:定时作业的设置方法
    URL Rewrite
    Asp.net 2.0 C#实现压缩/解压功能 [转=向作者‘肖相’无私共享精神致敬]
    网站的赢利模式 从只看排名流量中解脱出来[转]
    一些.net的工具[转]
    Expression孟岩
    sql作业,执行表间数据导入的实验
  • 原文地址:https://www.cnblogs.com/newera/p/9086579.html
Copyright © 2011-2022 走看看