• uoj132/BZOJ4200/洛谷P2304 [Noi2015]小园丁与老司机 【dp + 带上下界网络流】


    题目链接

    uoj132

    题解

    真是一道大码题,,,肝了一个上午

    老司机的部分是一个(dp),观察点是按(y)分层的,而且按每层点的上限来看可以使用(O(nd))(dp),其中(d)是每层的点数
    我们设(f[i])表示从(i)点进入该层,直到走完为止所经过的最多点的数量,我们把原点也看做一棵树,计算答案时减去即可
    转移只需枚举出点(j),假如(i)(j)的左侧,那么(j)及其左侧的点都能被经过,只需从(i)出发先走到左端点,再一直往右走到(j)
    我们还需预处理出每个点向三个方向能到达的下一个点,这个使用排序 + 离散化 + 桶即可
    具体地,向上记录(y),向左上记录(x + y),向右上记录(y - x)
    原理是利用一次方程(y = x + b)(y = -x + b)

    好了(dp)的部分解决了,稍微记录一下转移就可以输出方案

    现在我们解决小园丁的部分
    显而易见这是一个带上下界网络流
    对于可能出现的每条路径,都是一条流量下界为(1)的边
    建源汇点(S)(T)连向所有点
    然后建超级源汇点跑一遍最小可行流即可
    直接跑比较慢,需要用满流减去不加(T->S)的流量最大流
    口胡真容易

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (register int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (register int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 100005,maxm = 1000005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,x[maxn],y[maxn],val[maxn],val2[maxn],b[maxn],bi,tot;
    int nxtl[maxn],nxt[maxn],nxtr[maxn];
    int bac[maxn],id[maxn],sit[maxn];
    int L[maxn],R[maxn],pos[maxn],cnt;
    int f[maxn],Nxt[maxn],Out[maxn];
    int ok[maxn],d[maxn],vis[maxn],used[maxn],q[maxn],cur[maxn],head,tail,now;
    int df[maxn],h[maxn],ne = 1;
    struct EDGE{int to,nxt,f;}ed[maxm];
    inline void build(int u,int v,int w){
    	ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
    	ed[++ne] = (EDGE){u,h[v],0}; h[v] = ne;
    }
    void add(int u,int v){
    	Redge(u) if ((to = ed[k].to) == v) return;
    	ed[++ne] = (EDGE){v,h[u],INF}; h[u] = ne;
    	ed[++ne] = (EDGE){u,h[v],0}; h[v] = ne;
    	df[u]--; df[v]++; ok[v] = true;
    }
    inline bool cmp(const int& a,const int& b){
    	return val[a] == val[b] ? val2[a] < val2[b] : val[a] < val[b];
    }
    void preset(){
    	REP(i,n) id[i] = i,val[i] = y[i],b[++bi] = x[i];
    	sort(id + 1,id + 1 + n,cmp);
    	sort(b + 1,b + 1 + bi); tot = 1;
    	for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i];
    	for (int i = n; i; i--){
    		int u = id[i],X = lower_bound(b + 1,b + 1 + tot,x[u]) - b;
    		nxt[u] = bac[X];
    		bac[X] = u;
    	}
    	bi = 0; cls(bac);
    	REP(i,n) val[i] = x[i] + y[i],val2[i] = x[i],b[++bi] = x[i] + y[i];
    	sort(id + 1,id + 1 + n,cmp);
    	sort(b + 1,b + 1 + bi); tot = 1;
    	for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i];
    	for (int i = 1; i <= n; i++){
    		int u = id[i],V = lower_bound(b + 1,b + 1 + tot,x[u] + y[u]) - b;
    		nxtl[u] = bac[V];
    		bac[V] = u;
    	}
    	bi = 0; cls(bac);
    	REP(i,n) val[i] = y[i] - x[i],val2[i] = x[i],b[++bi] = y[i] - x[i];
    	sort(id + 1,id + 1 + n,cmp);
    	sort(b + 1,b + 1 + bi); tot = 1;
    	for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i];
    	for (int i = n; i; i--){
    		int u = id[i],V = lower_bound(b + 1,b + 1 + tot,y[u] - x[u]) - b;
    		nxtr[u] = bac[V];
    		bac[V] = u;
    	}
    	REP(i,n) val[i] = y[i];
    	sort(id + 1,id + 1 + n,cmp);
    	for (int i = 1; i <= n; i++){
    		int u = id[i]; sit[u] = i;
    		if (i == 1 || y[u] != y[id[i - 1]]){
    			L[++cnt] = i;
    			if (cnt > 1) R[cnt - 1] = i - 1;
    		}
    		pos[i] = cnt;
    	}
    	R[cnt] = n;
    }
    void work_dp(){
    	for (int i = L[cnt]; i <= n; i++) f[id[i]] = n - L[cnt] + 1;
    	for (int i = cnt - 1; i; i--){
    		int mx = 0,now,nowf,tmp,to,from; now = 0; from = 0;
    		for (int j = L[i]; j <= R[i]; j++){
    			int u = id[j];
    			tmp = 0; to = 0; from = 0;
    			if (nxt[u] && f[nxt[u]] > tmp) tmp = f[nxt[u]],to = nxt[u],from = u;
    			if (nxtl[u] && f[nxtl[u]] > tmp) tmp = f[nxtl[u]],to = nxtl[u],from = u;
    			if (nxtr[u] && f[nxtr[u]] > tmp) tmp = f[nxtr[u]],to = nxtr[u],from = u;
    			tmp++;
    			if (tmp > f[u]) f[u] = tmp,Nxt[u] = to,Out[u] = from;
    			tmp += R[i] - j;
    			if (mx > f[u]) f[u] = mx,Nxt[u] = now,Out[u] = nowf;
    			if (tmp > mx) mx = tmp,now = to,nowf = u;
    		}
    		mx = 0; now = 0; from = 0;
    		for (int j = R[i]; j >= L[i]; j--){
    			int u = id[j];
    			tmp = 0; to = 0; from = 0;
    			if (nxt[u] && f[nxt[u]] > tmp) tmp = f[nxt[u]],to = nxt[u],from = u;
    			if (nxtl[u] && f[nxtl[u]] > tmp) tmp = f[nxtl[u]],to = nxtl[u],from = u;
    			if (nxtr[u] && f[nxtr[u]] > tmp) tmp = f[nxtr[u]],to = nxtr[u],from = u;
    			tmp++;
    			if (tmp > f[u]) f[u] = tmp,Nxt[u] = to,Out[u] = nowf;
    			tmp += j - L[i];
    			if (mx > f[u]) f[u] = mx,Nxt[u] = now,Out[u] = nowf;
    			if (tmp > mx) mx = tmp,now = to,nowf = u;
    		}
    	}
    }
    void print(){
    	printf("%d
    ",f[n] - 1);
    	int u = Nxt[n],now,num = f[n] - 1;
    	while (u){
    		now = pos[sit[u]];
    		if (now == cnt){
    			printf("%d ",u),num--; if (!num) break;
    			for (int i = sit[u] - 1; num && i >= L[cnt]; i--){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    			for (int i = sit[u] + 1; num && i <= R[cnt]; i++){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    			break;
    		}
    		if (x[Out[u]] == x[u]){
    			printf("%d ",u),num--;
    		}
    		else if (x[Out[u]] <= x[u]){
    			for (int i = sit[u]; num && i <= R[now]; i++){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    			for (int i = sit[u] - 1; num && i >= sit[Out[u]]; i--){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    		}
    		else {
    			for (int i = sit[u]; num && i >= L[now]; i--){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    			for (int i = sit[u] + 1; num && i <= sit[Out[u]]; i++){
    				printf("%d ",id[i]),num--; if (!num) break;
    			}
    		}
    		if (!num) break;
    		u = Nxt[u];
    	}
    	puts("");
    }
    void solve1(){
    	preset();
    	work_dp();
    	print();
    }
    bool bfs(int S,int T){
    	q[head = tail = 0] = S; now++;
    	int u;
    	while (head <= tail){
    		u = q[head++];
    		Redge(u) if (ed[k].f && vis[to = ed[k].to] != now){
    			d[to] = d[u] + 1;
    			vis[to] = now;
    			q[++tail] = to;
    			if (to == T) return true;
    		}
    	}
    	return false;
    }
    int dfs(int u,int minf,int T){
    	if (u == T || !minf) return minf;
    	int f,flow = 0,to;
    	if (used[u] != now) used[u] = now,cur[u] = h[u];
    	for (int& k = cur[u]; k; k = ed[k].nxt)
    		if (vis[to = ed[k].to] == now && d[to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f),T))){
    			ed[k].f -= f; ed[k ^ 1].f += f;
    			flow += f; minf -= f;
    			if (!minf) break;
    		}
    	return flow;
    }
    void work_sol(int u){
    	int S = pos[sit[u]],l = L[S],r = R[S],a,b,c,v,sum;
    	for (int i = l; i <= r; i++){
    		v = id[i]; a = nxtl[v]; b = nxt[v]; c = nxtr[v];
    		if (v == u){
    			if (a && f[a] + 1 == f[u]) add(v,a);
    			if (b && f[b] + 1 == f[u]) add(v,b);
    			if (c && f[c] + 1 == f[u]) add(v,c);
    			continue;
    		}
    		if (sit[v] < sit[u]) sum = r - sit[v] + 1;
    		else sum = sit[v] - l + 1;
    		if (a && f[a] + sum == f[u]) add(v,a);
    		if (b && f[b] + sum == f[u]) add(v,b);
    		if (c && f[c] + sum == f[u]) add(v,c);
    	}
    }
    void setG(){
    	ok[n] = true;
    	for (int i = 1; i < cnt; i++){
    		for (int j = L[i]; j <= R[i]; j++)
    			if (ok[id[j]]) work_sol(id[j]);
    	}
    }
    void solve2(){
    	setG();
    	int S = n + 1,T = n + 2,ans = 0;
    	for (int i = 1; i <= n; i++){
    		if (!df[i]) continue;
    		if (df[i] > 0) ans += df[i],build(S,i,df[i]);
    		else build(i,T,-df[i]);
    	}
    	while (bfs(S,T)) ans -= dfs(S,INF,T);
    	printf("%d
    ",ans);
    }
    int main(){
    	n = read();
    	REP(i,n) x[i] = read(),y[i] = read();
    	n++;
    	solve1();
    	solve2();
    	return 0;
    }
    
    
  • 相关阅读:
    Java Web(5) Spring 下使用Junit4 单元测试
    聊聊单元测试(三)——Spring Test+JUnit完美组合
    浅谈ELK日志分析平台
    ELK 实现 Java 分布式系统日志分析架构
    ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台
    开源分布式搜索平台ELK(Elasticsearch+Logstash+Kibana)入门学习资源索引
    自动补全下拉框(可输入匹配的下拉框)
    这是一篇满载真诚的微信小程序开发干货
    微服务化的多组件项目,跨地域、分布式版本管理和发布方式
    解放双手,发掘更大的价值:智能化运维
  • 原文地址:https://www.cnblogs.com/Mychael/p/9233317.html
Copyright © 2020-2023  润新知