zoukankan      html  css  js  c++  java
  • [题解] [JSOI2010] 挖宝藏

    题面

    题解

    我们发现挖掘一个点所需要的方块是一个向上的倒三角, 我们设这个倒三角在 (y = -1) 上的左右端点分别为 (l, r)
    不难发现, 一个 ([l, r]) 区间仅对应一个点, 也就是说, 每个点所需要的倒三角都是不同的
    如果一个区间被另外一个区间完全覆盖, 那么选了大的那个区间, 小区间的贡献就可以直接加上了, 而不需要算选小区间的代价
    同理, 若两个区间相交, 那么选这两个区间的利润就是他们的贡献减去他们的代价再加上重复部分的代价
    因为这一部分被多减了一次
    但是从这里又会发现一个问题, 若两个区间同时完全覆盖一个小区间, 并且这个两个区间重叠的区间也完全覆盖这个小区间
    那这个小区间的贡献又会被多算一次, 要减掉
    我们把区间按照右端点排序, 并预处理出每个区间完全覆盖的区间, 将贡献加上去
    (f[i]) 代表前 (i) 个区间, (i) 必选的最大利润
    考虑枚举 (j)
    (j) 区间被 (i) 区间完全覆盖, 贡献已经算进 (i) 区间了, 不从这种 (j) 转移
    (j) 区间与 (i) 区间有交, 减去交的这一部分的重复贡献, 加上交的这一部分的重复代价
    (j) 区间与 (i) 区间无交, 直接加上 (j) 的利润即可
    这样子是 (O(n^3))
    考虑优化算重复贡献的部分, 发现右端点单调不降, 拿个指针维护一下即可

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    int n, f[1005], ans, cnt, r; 
    struct node
    {
    	int l, r, v1, v2, c;
    	bool operator < (const node &p) const
    		{
    			return r == p.r ? l < p.l : r < p.r; 
    		}
    } p[1005]; 
    
    template < typename T >
    inline T read()
    {
    	T x = 0, w = 1; char c = getchar();
    	while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * w; 
    }
    
    int calc(int r, int l)
    {
    	int res = (r + l) & 1;
    	return (r - l + 2 + res) * (r - l + 2 - res) / 4; 
    }
    
    int main()
    {
    	n = read <int> ();
    	for(int x, y, i = 1; i <= n; i++)
    	{
    		x = read <int> (), y = read <int> ();
    		p[i].l = x + y + 1, p[i].r = x - y - 1;
    		p[i].v1 = read <int> (), p[i].c = calc(p[i].r, p[i].l); 
    	}
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			if(p[j].l >= p[i].l && p[j].r <= p[i].r)
    				p[i].v2 += p[j].v1;
    	sort(p + 1, p + n + 1); 
    	f[0] = 0;
    	for(int i = 1; i <= n; i++)
    	{
    		f[i] = p[i].v2 - p[i].c, r = 1, cnt = 0; 
    		for(int tmp, j = 1; j < i; j++)
    		{
    			if(p[j].r >= p[i].l && p[j].l < p[i].l)
    			{
    				while(r <= i && p[r].r <= p[j].r)
    				{
    					if(p[r].l >= p[i].l)
    						cnt += p[r].v1;
    					r++; 
    				}
    				tmp = calc(p[j].r, p[i].l); 
    				f[i] = max(f[i], f[j] + p[i].v2 - p[i].c + tmp - cnt); 
    			}
    			if(p[j].r < p[i].l)
    				f[i] = max(f[i], f[j] + p[i].v2 - p[i].c); 
    		}
    	}
    	for(int i = 0; i <= n; i++)
    		ans = max(ans, f[i]);
    	printf("%d
    ", ans); 
    	return 0; 
    }
    /*
    5
    1 -1 2
    0 -1 2
    4 -1 1
    3 -1 2
    2 -1 2
     */
    
  • 相关阅读:
    linux音频alsa-uda134x驱动文档阅读之一转自http://blog.csdn.net/wantianpei/article/details/7817293
    linux音频alsa-uda134x驱动分析之二(时钟)
    linux下定时器介绍1
    linux下定时器介绍2--timer_create等函数集的使用示例
    linux 获取时间后--自定义时间格式
    linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction
    高通QMI协议
    linux sigaction 函数 用法释义
    NB-iot 和 emtc两种技术区别
    如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12258615.html
Copyright © 2011-2022 走看看