zoukankan      html  css  js  c++  java
  • 【神仙题】【CF28D】 Don't fear, DravDe is kind

    传送门

    Description

    一个有N辆卡车的车队从城市Z驶向城市3,来到了一条叫做“恐惧隧道”的隧道。在卡车司机中,有传言说怪物DravDe在那条隧道里搜寻司机。有些司机害怕先走,而其他人则害怕后走。但让我们考虑一般情况,每辆卡车用四个数字描述:

    •v,卡车的价值,包括乘客和货物
    •c,乘客数量,包括司机本人
    •l,当前辆卡车之前应该进入的隧道的总人数,这样,当前司机就可以克服他的恐惧(如果怪物出现在那辆车前面,它会先吃掉他们)
    •r,当前辆卡车之后应该进入的隧道的总人数,这样,当前司机就可以克服他的恐惧(如果怪物出现在那辆车后面,它会先吃掉他们)

    由于路面很窄,如果 DravDe 一旦出现,就不可能逃离。此外,车队不能重新安排。卡 车的顺序是不能改变的,但是有卡车会停留在隧道附近无限期。你,作为车队的头儿,应该 把一些卡车移走(是的,忽略这些卡车的价值),这样车队的其余部分可以通过隧道。求移 走一些卡车后,剩余卡车的总价值最大是多少。

    Input

    第一行是卡车个数(n)

    下面(n)行,每行四个数,按照上述顺序给出卡车的四个参数

    Output

    共输出两行。第一行输出代表价值最大时剩余的卡车数量

    第二行输出被选择的卡车编号。任意输出一种即可

    Hint

    (0~leq~v~leq~10^4)(0~leq~)其他参数(leq~10^5)

    Solution

    经过一番深思熟虑,我们发现对于同时被选择的两辆车,总的人数应该是(c+r+l)。于是得出结论,被同时选择的车上述参数和应该相同。

    于是这告诉我们只有满足上述条件才能更新答案,以及对于一辆车,他所在的被选择的序列的人数应该是固定的。

    显然这是一个线性DP。于是有转移方程(f_i=max{f_j}+v_i),其中满足(j)的参数和与(i)相同,同时因为(j)(i)的前面,于是有(l_j+c_i=l_i)。按照这个方程即可进行转移。每枚举到一个(r=0)的位置就可以更新答案。

    Code

    #include<map>
    #include<cstdio>
    #include<algorithm>
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch=getchar(),lst=' ';
    	while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    	while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst == '-') x=-x;
    }
    
    namespace IO {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x,const char aft,const bool pt) {
    	if(x < 0) {x=-x,putchar('-');}
    	rg int top=0;
    	do {IO::buf[++top]=x%10+'0';} while(x/=10);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {return a > b ? a : b;}
    template <typename T>
    inline T mmin(const T a,const T b) {return a < b ? a : b;}
    template <typename T>
    inline T mabs(const T a) {return a < 0 ? -a : a;}
    
    template <typename T>
    inline void mswap(T &_a,T &_b) {
    	T _temp=_a;_a=_b;_b=_temp;
    }
    
    const int maxn = 400010;
    
    struct M {
    	int v,c,l,r,sum,pos;
    	inline bool operator<(const M &_others) const {
    		if(this->sum != _others.sum) return this->sum < _others.sum;
    		return this->pos < _others.pos;
    	}
    };
    M MU[maxn];
    
    int n,ans;
    int frog[maxn],pre[maxn],pcnt[maxn];
    std::map<int,int>mp[maxn];
    
    void dfs(ci);
    
    int main() {
    	qr(n);
    	for(rg int i=1;i<=n;++i) {
    		M &now=MU[i];
    		qr(now.v);qr(now.c);qr(now.l);qr(now.r);
    		now.sum=now.c+now.l+now.r;now.pos=i;
    	}
    	std::sort(MU+1,MU+1+n);
    	for(rg int i=1;i<=n;++i) {
    		int k;
    		if(!MU[i].l) {
    			frog[i]=MU[i].v;pcnt[i]=1;
    		}
    		else if((k=mp[MU[i].sum][MU[i].l]) != 0) {
    			frog[i]=frog[k]+MU[i].v;pre[i]=k;pcnt[i]=pcnt[k]+1;
    		}
    		if(frog[i] && (frog[i] > frog[mp[MU[i].sum][MU[i].c+MU[i].l]])) mp[MU[i].sum][MU[i].l+MU[i].c]=i;
    		if(!(MU[i].r) && (frog[ans] < frog[i])) ans=i;
    	}
    	qw(pcnt[ans],'
    ',true);
    	dfs(ans);putchar('
    ');
    	return 0;
    }
    
    void dfs(ci x) {
    	if(!x) return;
    	dfs(pre[x]);
    	qw(MU[x].pos,' ',true);
    }
    

    Summary

    在DP转移时,可以通过代数恒等式证明出一种正确的转移方法。

  • 相关阅读:
    Python入门11 —— 基本数据类型的操作
    Win10安装7 —— 系统的优化
    Win10安装6 —— 系统的激活
    Win10安装5 —— 系统安装步骤
    Win10安装4 —— 通过BIOS进入PE
    Win10安装2 —— 版本的选择与下载
    Win10安装1 —— 引言与目录
    Win10安装3 —— U盘启动工具安装
    虚拟机 —— VMware Workstation15安装教程
    Python入门10 —— for循环
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9879795.html
Copyright © 2011-2022 走看看