• IOI2021集训队作业 247OK The Imp


    有一堆商品,每个价值为(v_i),代价为(c_i)。收益定义为价值减代价。

    你要买一个商品,但是有个小鬼会捣乱,他有(k)次机会使得你正在买的商品的价值变为(0),这时候你不得不重买一遍。

    你和小鬼都聪明绝顶,求最终你的收益。

    (nle 1.5*10^5,kle 9)


    考虑最终的选择策略,即一个选择商品的序列。你按照这个序列选,使得小鬼怎么搞最终的答案都不会更劣。

    假如已经知道了这个序列的组成,现在要排序:假如相邻的两个商品(a)(b)(a)在前(b)在后比反过来优,那么有:(min(v_b-c_b-v_a,0)+v_a-c_a>min(v_a-c_a-v_b,0)+v_b-c_b)。拆开来分类讨论一下,发现这等价于(v_a<v_b)

    我没有把式子拆完整发现这个东西有传递性而一开始不会证QAQ。

    先排序,于是就可以DP了。由于正着DP需要记(sum c_i)比较难受,所以可以倒着DP,每次枚举这一位选或不选,看看小鬼是否在这一位搞,即(f_{i,j})表示搞完([i,n]),小鬼搞了(j)次的答案。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 150005
    #define INF 1000000000
    int n,k;
    struct item{
    	int v,c;
    } a[N];
    bool cmp(item a,item b){
    //	return min(b.w-a.v,0)+a.w>min(a.w-b.v,0)+b.w;
    	return a.v<b.v;
    }
    int f[N][10];
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d%d",&n,&k);
    		for (int i=1;i<=n;++i)
    			scanf("%d%d",&a[i].v,&a[i].c);
    		if (n<=k){
    			printf("0
    ");
    			continue;
    		}
    		sort(a+1,a+n+1,cmp);
    		for (int j=1;j<=k;++j)
    			f[n+1][j]=0;
    		f[n+1][0]=0;
    		for (int i=n;i>=1;--i){
    			f[i][0]=max(f[i+1][0],a[i].v-a[i].c);
    			for (int j=1;j<=k;++j)
    				f[i][j]=max(f[i+1][j],min(a[i].v-a[i].c,f[i+1][j-1]-a[i].c));
    		}
    //		for (int i=1;i<=n;++i,printf("
    ")){
    //			for (int j=0;j<=k;++j)
    //				printf("%d ",f[i][j]);
    //		}
    		printf("%d
    ",f[1][k]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Django请求的生命周期图解及流程
    Django中请求的生命周期
    127.0.0.1和0.0.0.0和本机IP的区别
    Linux中errno的含义
    wireshark 过滤表达式
    GDB调试
    【LinuxShell】grep用法详解
    Linux下 tftp 服务器的安装与使用
    设备掐断重启
    GDB disassemble
  • 原文地址:https://www.cnblogs.com/jz-597/p/13958474.html
Copyright © 2020-2023  润新知