zoukankan      html  css  js  c++  java
  • P7302 [NOI1998] 免费的馅饼

    (一)思路

    题意不再赘述。第一眼就觉得是动态规划。

    (f(i))表示接到第(i)个馅饼能够得到的最大价值。由于一个人每次最多只能移动一格。设上一次接到的馅饼在(p_j),当前要接的馅饼在(p_i),那么,如果能同时接到馅饼(i,j),必要条件是:(|p_i-p_j|leq 2(t_i-t_j),t_i-t_jge0)

    因此,状态转移方程可以表示为:

    (f(i)=val(i)+sumlimits_{|p_i-p_j|leq 2(t_i-t_j)}f(j))

    (val(i))是第(i)个馅饼的价值。

    因为:

    [|p_i-p_j|leq 2(t_i-t_j)iff egin{cases} 2t_j-p_jleq 2t_i-p_i \ 2t_j+p_jleq 2t_i-p_iend{cases} ]

    所以:

    [displaystyle f(i)=val(i)+sumlimits_{2t_j-p_jleq 2t_i-p_i wedge2t_j+p_jleq 2t_i+p_i}f(j) ]

    (二)实现

    不难发现,上面的约束条件其实是一个二维偏序。因此,可以用树状数组/CDQ分治等算法和数据结构水过。由于我过于愚钝,开始没注意到二位偏序的关系,惨遭WA。

    数据结构的具体做法是,先按照一维排序,然后再用数据结构维护第二维。

    (三)代码

    @pythoner713 巨佬强烈要求发代码。

    下面是动态开点线段树的代码(因为我懒得写离散化)。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 5;
    inline int read(){
    	int w = 0, f = 1; char ch = getchar();
    	while(ch < '0' or ch > '9') {if(ch == '-') f = -f; ch = getchar();}
    	while(ch >= '0' and ch <= '9') w = w*10 + ch - '0', ch = getchar();
    	return w*f;
    }
    struct SegmentTree{
    	int ls, rs, dat;
    }t[maxn*30];
    int tot;
    void update(int p){
    	t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
    }
    void insert(int &p, int L, int R, int x, int val){
    	if(!p) p = ++tot;
    	if(L == R){
    		t[p].dat = max(t[p].dat, val);
    		return ;
    	}
    	int mid = (L+R)>>1;
    	if(x <= mid) insert(t[p].ls, L, mid, x, val);
    	else insert(t[p].rs, mid+1, R, x, val);
    	update(p);
    }
    int ask(int p, int L, int R, int l, int r){
    	if(!p) return 0;
    	if(l <= L and r >= R){
    		return t[p].dat;
    	}
    	int mid = (L+R)>>1, val = 0;
    	if(l <= mid) val = max(val, ask(t[p].ls, L, mid, l, r));
    	if(r > mid) val = max(val, ask(t[p].rs, mid+1, R, l, r));
    	return val; 
    }
    struct PIE{
    	int t, p, v;
    	inline bool operator <(const PIE& x) const{
    		return 2*t + p < 2*x.t + x.p;
    	} 
    }pie[maxn];
    int N, W;
    signed main(){
    	tot = 1; int root = 1;
    	W = read()<<1, N = read();
    	for(int i=1, x, y, z; i <= N; i++){
    		x = read(), y = read(), z = read(); 
    		pie[i] = (PIE){x, y, z};
    	}
    	sort(pie+1, pie+N+1);
    	for(int i=1; i<=N; i++){
    		int val = ask(1, -W, W, -W, 2*pie[i].t - pie[i].p) + pie[i].v;
    		insert(root, -W, W, 2*pie[i].t - pie[i].p, val);
    	}
    	cout<<t[1].dat<<endl;
    	return 0;
    }
    
  • 相关阅读:
    【题解】一本通例题 S-Nim
    【题解】一本通例题 取石子游戏
    【题解】[USACO09NOV]A Coin Game S
    【题解】取火柴游戏
    【题解】CF375D Tree and Queries
    Linux sudo用户提权与日志审计
    No space left on device
    CentOS下多种方法显示文本行号
    Python之行-01之初识python
    约瑟夫问题
  • 原文地址:https://www.cnblogs.com/GDOI2018/p/14601915.html
Copyright © 2011-2022 走看看