• [题解] [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
     */
    
  • 相关阅读:
    PDA智能程序访问WebService,报告“未能建立与网络的连接”
    VS2008中开发智能设备程序的一些总结收藏
    Error: The INF file contains Unicode characters that could not be converted correctly
    在vs2008工程中制作cab包
    linux专题三之如何悄悄破解root密码(以redhat7.2x64为例)
    linux专题一之文件描述符、重定向、管道符、tee命令
    linux的计划
    如何安装RHEL7.2x64 即红帽7.2虚拟机?
    快速排序及查找第K个大的数。
    来来来,做道题,一起防老年痴呆
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12258615.html
Copyright © 2020-2023  润新知