zoukankan      html  css  js  c++  java
  • UOJ#132&bzoj4200[Noi2015]小园丁与老司机

    看,这是一个传送门


    Part A

    把坐标离散化,按照纵坐标为第一关键字,横坐标为第二关键字排序

    以$f_i$记录来到$i$这个点最多经过点数,那么答案显而易见就是$f_i$加上该层点数

    转移的话就是分三种来到这个点的方案

    对于每一种考虑:

    1)直接上来

    2)通过左边某个点上来,把左边所有点都走完

    3)通过右边某个点上来,把右边所有点都走完

    然后对于每一层维护从左边来的最大值和从右边来的最大值即可


    Part B

    从任意一个满足答案的结束点往开始点沿任意有效路径走即可


    Part C

    很显然,找到所有有可能经过的边做最小路径覆盖就是答案了

    同样很显然要去维护每个点所有有可能的前置点也是不可能的..

    那么就去用一种比较奥妙重重的方法

    比如说对于你已经知道了$u->v$这一条边是要走的,那么对于$u$来说:

    1)如果$f_u+1=f_v$,直接标记$u$

    2)如果从左(右)边某个点走上来的,那么标记$u$点前(后)一个表示该点前(后)的最大值都应被标记

    等到去扫那一层的时候再去标记那些点

    这样即可做到$O(n)$的时间复杂度

    对于最小路径覆盖,可以用普通网络流和上下界最小流..

    但是普通网络流貌似要大一点..

    因为这个上下界最小流保证可行,所以并不需要再加$ed->st$的边来求

    直接把总流量和现流量一减就行了..


    Code

    花了两天怒敲6k+..

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int Maxn = 50010;
    const int inf = 0x7fffffff;
    int s[3][Maxn];
    int b[3][Maxn], bl[3];
    int bb[Maxn], bbl;
    int begin[Maxn], end[Maxn], sy[Maxn];
    int f[Maxn], Maxl[Maxn], Maxlnum[Maxn], Maxr[Maxn], Maxrnum[Maxn];
    int pre[3][Maxn];
    int lj[Maxn], ljl;
    bool vl[Maxn], vr[Maxn], v[Maxn];
    struct enode {
    	int y, next, c, opp;
    }a[Maxn*18]; int first[Maxn], len;
    int st, ed, sst, eed, d[Maxn];
    int h[Maxn];
    void ins(int x, int y, int c) {
    	len++; int k1 = len;
    	a[len].y = y; a[len].c = c;
    	a[len].next = first[x]; first[x] = len;
    	len++; int k2 = len;
    	a[len].y = x; a[len].c = 0;
    	a[len].next = first[y]; first[y] = len;
    	a[k1].opp = k2;
    	a[k2].opp = k1;
    }
    int _max(int x, int y) { return x > y ? x : y; }
    int _min(int x, int y) { return x < y ? x : y; }
    bool bfs() {
    	queue <int> q;
    	memset(h, -1, sizeof(h));
    	h[sst] = 0;
    	q.push(sst);
    	while(!q.empty()){
    		int x = q.front(); q.pop();
    		for(int k = first[x]; k; k = a[k].next){
    			int y = a[k].y;
    			if(h[y] == -1 && a[k].c > 0){
    				h[y] = h[x]+1;
    				q.push(y);
    			}
    		}
    	}
    	return h[eed] > 0;
    }
    int dfs(int x, int flow) {
    	if(x == eed) return flow;
    	int delta = 0;
    	for(int k = first[x]; k; k = a[k].next){
    		int y = a[k].y;
    		if(h[y] == h[x]+1 && a[k].c > 0 && flow-delta > 0){
    			int minf = dfs(y, _min(a[k].c, flow-delta));
    			delta += minf;
    			a[k].c -= minf;
    			a[a[k].opp].c += minf;
    		}
    	}
    	if(delta == 0) h[x] = -1;
    	return delta;
    }
    struct node {
    	int x, y, num, p[3];
    }list[Maxn];
    bool cmp(node x, node y) {
    	if(x.y != y.y) return x.y < y.y;
    	return x.x < y.x;
    }
    int n;
    int main() {
    	int i, j, k;
    	scanf("%d", &n);
    	for(i = 1; i <= n; i++){
    		scanf("%d%d", &list[i].x, &list[i].y);
    		list[i].num = i;
    		b[0][i] = list[i].p[0] = list[i].x-list[i].y;
    		b[1][i] = list[i].p[1] = list[i].x;
    		b[2][i] = list[i].p[2] = list[i].x+list[i].y;
    		bb[i] = list[i].y;
    	}
    	n++;
    	sort(list+1, list+n+1, cmp);
    	for(i = 0; i < 3; i++){
    		sort(b[i]+1, b[i]+n+1);
    		bl[i] = unique(b[i]+1, b[i]+n+1) - (b[i]+1);
    	}
    	sort(bb+1, bb+n+1);
    	bbl = unique(bb+1, bb+n+1) - (bb+1);
    	int l = 1;
    	sy[1] = 1;
    	for(i = 2; i <= n; i++){
    		if(list[i].y != list[i-1].y) l++;
    		sy[i] = l;
    	}
    	j = 1;
    	for(i = 1; i <= bbl; i++){
    		begin[i] = j;
    		while(list[j].y == bb[i] && j <= n) j++;
    		end[i] = j-1;
    	}
    	//Part A
    	for(i = 2; i <= n; i++) f[i] = -1;
    	int p0;
    	for(i = 0; i < 3; i++){
    		p0 = lower_bound(b[i]+1, b[i]+bl[i]+1, 0) - b[i];
    		s[i][p0] = 1;
    	}
    	Maxl[1] = -1; Maxlnum[1] = 1; Maxr[1] = 1; Maxrnum[1] = 1;
    	for(i = 2; i <= bbl; i++){
    		int p, o, u, v;
    		for(j = begin[i]; j <= end[i]; j++){
    			for(k = 0; k < 3; k++){
    				p = lower_bound(b[k]+1, b[k]+bl[k]+1, list[j].p[k]) - b[k];
    				if(s[k][p] > 0){
    					u = s[k][p]; pre[k][j] = u;
    					o = sy[u];
    					if(f[u] != -1) f[j] = _max(f[j], f[u]+1);
    					if(u != begin[o] && Maxlnum[u-1] > 0) f[j] = _max(f[j], Maxl[u-1]+u-begin[o]+1);
    					if(u != end[o] && Maxrnum[u+1] > 0) f[j] = _max(f[j], Maxr[u+1]+end[o]-u+1);
    				}
    				s[k][p] = j;
    			}
    		}
    		if(f[begin[i]] > 0){
    			Maxl[begin[i]] = f[begin[i]];
    			Maxlnum[begin[i]] = begin[i];
    		}
    		for(j = begin[i]+1; j <= end[i]; j++){
    			Maxl[j] = Maxl[j-1]; Maxlnum[j] = Maxlnum[j-1];
    			if((f[j] >= Maxl[j] || Maxlnum[j] == 0) && f[j] > 0){
    				Maxl[j] = f[j];
    				Maxlnum[j] = j;
    			}
    		}
    		if(f[end[i]] > 0){
    			Maxr[end[i]] = f[end[i]];
    			Maxrnum[end[i]] = end[i];
    		}
    		for(j = end[i]-1; j >= begin[i]; j--){
    			Maxr[j] = Maxr[j+1]; Maxrnum[j] = Maxrnum[j+1];
    			if((f[j] >= Maxr[j] || Maxrnum[j] == 0) && f[j] > 0){
    				Maxr[j] = f[j];
    				Maxrnum[j] = j;
    			}
    		}
    	}
    	int ans = 0, now = 1;
    	for(i = 2; i <= n; i++){
    		if(f[i]+end[sy[i]]-begin[sy[i]] > ans){
    			ans = f[i]+end[sy[i]]-begin[sy[i]];
    			now = i;
    		}
    	}
    	printf("%d
    ", ans);
    	//Part B
    	ljl = 0;
    	for(i = end[sy[now]]; i > now; i--) lj[++ljl] = list[i].num;
    	for(i = begin[sy[now]]; i < now; i++) lj[++ljl] = list[i].num;
    	while(now != 1){
    		lj[++ljl] = list[now].num;
    		int u;
    		for(k = 0; k < 3; k++){
    			u = pre[k][now];
    			if(u > 0){
    				if(f[u]+1 == f[now]){ now = u; break; }
    				if(u != begin[sy[u]] && Maxl[u-1]+u-begin[sy[u]]+1 == f[now] && Maxlnum[u-1] > 0){
    					for(i = u; i > Maxlnum[u-1]; i--) lj[++ljl] = list[i].num;
    					for(i = begin[sy[u]]; i < Maxlnum[u-1]; i++) lj[++ljl] = list[i].num;
    					now = Maxlnum[u-1];
    					break;
    				}
    				if(u != end[sy[u]] && Maxr[u+1]+end[sy[u]]-u+1 == f[now] && Maxrnum[u+1] > 0){
    					for(i = u; i < Maxrnum[u+1]; i++) lj[++ljl] = list[i].num;
    					for(i = end[sy[u]]; i > Maxrnum[u+1]; i--) lj[++ljl] = list[i].num;
    					now = Maxrnum[u+1];
    					break;
    				}
    			}
    		}
    	}
    	for(i = ljl; i > 1; i--) printf("%d ", lj[i]);
    	if(ljl >= 1) printf("%d", lj[1]);
    	printf("
    ");
    	//Part C
    	for(i = 2; i <= n; i++){
    		if(f[i]+end[sy[i]]-begin[sy[i]] == ans) v[i] = true;
    	}
    	st = n+1; ed = st+1; sst = ed+1; eed = sst+1;
    	for(i = bbl; i >= 1; i--){
    		int bjm, u;
    		bjm = n+1;
    		for(j = end[i]; j >= begin[i]; j--){
    			if(vl[j] == true) bjm = Maxl[j];
    			if(f[j] == bjm) v[j] = true;
    		}
    		bjm = n+1;
    		for(j = begin[i]; j <= end[i]; j++){
    			if(vr[j] == true) bjm = Maxr[j];
    			if(f[j] == bjm) v[j] = true;
    		}
    		for(j = begin[i]; j <= end[i]; j++){
    			if(v[j] == false) continue;
    			for(k = 0; k < 3; k++){
    				u = pre[k][j];
    				if(u == 0) continue;
    				bool bk = false;
    				if(f[u]+1 == f[j]) v[u] = true, bk = true;
    				if(u != begin[sy[u]] && Maxl[u-1]+u-begin[sy[u]]+1 == f[j] && Maxlnum[u-1] > 0){
    					vl[u-1] = true;
    					bk = true;
    				}
    				if(u != end[sy[u]] && Maxr[u+1]+end[sy[u]]-u+1 == f[j] && Maxrnum[u+1] > 0){
    					vr[u+1] = true;
    					bk = true;
    				}
    				if(bk == true){
    					d[j]++; d[u]--;
    					ins(u, j, inf-1);
    				}
    			}
    		}
    	}
    	int sum = 0;
    	for(i = 1; i <= n; i++){
    		ins(st, i, inf);
    		ins(i, ed, inf);
    		if(d[i] > 0) ins(sst, i, d[i]), sum += d[i];
    		else ins(i, eed, -d[i]);
    	}
    	int delta = 0;
    	while(bfs()) delta += dfs(sst, inf);
    	printf("%d
    ", sum-delta);
    	/*ins(ed, st, inf);
    	while(bfs()) delta += dfs(sst, inf);
    	printf("%d
    ", a[len].c);*/
    	return 0;
    }
    

      


    最后说点什么..

    这道题是真的搞了很久

    在不停的考虑细节、修改、压缩..

    看到这个也是满满的感动..

  • 相关阅读:
    testng遇到的一些问题
    Redis-常用命令总结
    Spring AOP
    Spring IOC
    Java-J.U.C总结
    Java-将map拼接成“参数=值&参数=值”
    java多线程-线程池
    mysql 二进制文件增量备份
    Centos下mysql数据库备份与恢复的方法
    CentOS下mysql默认安装位置
  • 原文地址:https://www.cnblogs.com/darklove/p/6425680.html
Copyright © 2011-2022 走看看