1. 程式人生 > >【NOI2015】小園丁與老司機

【NOI2015】小園丁與老司機

dp+有源匯上下界的最小流;
dp:按pair

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=(n);i++)
#define rep2(i,k,n) for(int i=k;i>=(n);i--)
using namespace std;
const int N=50305;
const int M=600005;
const int inf=0x3f3f3f3f;
struct node{
    int x,y,id;node(int x=0,int y=0,int id=0):x(x),y(y),id(id){}
}a[N];
bool
cmp(node A,node B){ return A.y==B.y ? A.x<B.x : A.y<B.y; } int n; map<int,int> mp1,mp2,mp3; int f[N],fa[N],from[N],mx[N],pos,tag[N],stk[N],top,f2[N],ans,in[N],out[N]; int S,T,SS,TT,cur[N],Sum=0; void dp1(){ memset(f,-0x7f,sizeof(f)); memset(mx,-0x7f,sizeof(f)); f[0]=0; int
t=0; for(int i=0;i<=n;i=++t){ while(t<n && a[t+1].y==a[t].y)t++; rep(j,i,t){ if(mp1.find(a[j].x+a[j].y)!=mp1.end()){ int p=mp1[a[j].x+a[j].y]; if(f[p]+1>f[j])f[j]=f[p]+1,fa[j]=p; } mp1[a[j].x+a[j].y]=j; if
(mp2.find(a[j].x-a[j].y)!=mp2.end()){ int p=mp2[a[j].x-a[j].y]; if(f[p]+1>f[j])f[j]=f[p]+1,fa[j]=p; } mp2[a[j].x-a[j].y]=j; if(mp3.find(a[j].x)!=mp3.end()){ int p=mp3[a[j].x]; if(f[p]+1>f[j])f[j]=f[p]+1,fa[j]=p; } mp3[a[j].x]=j; } int now=-1; rep(j,i+1,t){ if(now==-1||f[j-1]>f[now])now=j-1; if(f[now]+j-i>mx[j])mx[j]=f[now]+j-i,from[j]=now; } now=-1; rep2(j,t-1,i){ if(now==-1||f[j+1]>f[now])now=j+1; if(f[now]+t-j>mx[j])mx[j]=f[now]+t-j,from[j]=now; } rep(j,i,t)if(mx[j]>f[j])f[j]=mx[j],tag[j]=1; } pos=0; rep(i,1,n)if(!pos||f[i]>f[pos])pos=i; } void dp2(){ mp1.clear(),mp2.clear(),mp3.clear(); memset(f2,-0x7f,sizeof(f2)); memset(mx,-0x7f,sizeof(f)); rep(i,1,n)if(f[i]==ans)f2[i]=1; int t=n; for(int i=n;i>=0;i=--t){ while(t && a[t-1].y==a[t].y)t--; rep2(j,i,t){ if(mp1.find(a[j].x+a[j].y)!=mp1.end()){ int p=mp1[a[j].x+a[j].y]; if(f2[p]+1>f2[j])f2[j]=f2[p]+1; } mp1[a[j].x+a[j].y]=j; if(mp2.find(a[j].x-a[j].y)!=mp2.end()){ int p=mp2[a[j].x-a[j].y]; if(f2[p]+1>f2[j])f2[j]=f2[p]+1; } mp2[a[j].x-a[j].y]=j; if(mp3.find(a[j].x)!=mp3.end()){ int p=mp3[a[j].x]; if(f2[p]+1>f2[j])f2[j]=f2[p]+1; } mp3[a[j].x]=j; } int now=-1; rep(j,t+1,i){ if(now==-1||f2[j-1]+i-j+1>f2[now]+i-now)now=j-1; if(f2[now]+i-now>mx[j])mx[j]=f2[now]+i-now; } now=-1; rep2(j,i-1,t){ if(now==-1||f2[j+1]+j+1-t>f2[now]+now-t)now=j+1; if(f2[now]+now-t>mx[j])mx[j]=f2[now]+now-t; } rep(j,t,i)if(mx[j]>f2[j])f2[j]=mx[j]; } } void print(int x,int y){ if(x<y){ int lx=x; while(lx>=0 && a[lx].y==a[y].y)printf("%d ",a[lx].id),lx--; int rx=x+1; while(rx<=y && a[rx].y==a[y].y)printf("%d ",a[rx].id),rx++; }else{ int rx=x; while(rx<=n && a[rx].y==a[y].y)printf("%d ",a[rx].id),rx++; int lx=x-1; while(lx>=y && a[lx].y==a[y].y)printf("%d ",a[lx].id),lx--; } } void solve(){ printf("%d\n",ans=f[pos]); top=0; int now=pos; while(now!=-1){ if(now)stk[++top]=now; if(tag[now]){ stk[++top]=from[now]; now=fa[from[now]]; }else now=fa[now]; } while(top){ if(a[stk[top]].y==a[stk[top-1]].y)print(stk[top],stk[top-1]),top--; else printf("%d ",a[stk[top]].id); top--; } printf("\n"); } struct E{ int to,next,cap;E(int to=0,int next=0,int cap=0):to(to),next(next),cap(cap){} }edge[M]; int head[N],tot=1; void add(int x,int y,int cap){ edge[++tot]=E(y,head[x],cap);head[x]=tot; edge[++tot]=E(x,head[y],0);head[y]=tot; } void build(){ mp1.clear(),mp2.clear(),mp3.clear(); S=n+1,T=S+1,SS=T+1,TT=SS+1; rep(i,0,n){ if(mp1.find(a[i].x+a[i].y)!=mp1.end()){ int p=mp1[a[i].x+a[i].y]; if(f[p]+f2[i]==ans){ add(p,i,inf); out[p]++; in[i]++; } } mp1[a[i].x+a[i].y]=i; if(mp2.find(a[i].x-a[i].y)!=mp2.end()){ int p=mp2[a[i].x-a[i].y]; if(f[p]+f2[i]==ans){ add(p,i,inf); out[p]++; in[i]++; } } mp2[a[i].x-a[i].y]=i; if(mp3.find(a[i].x)!=mp3.end()){ int p=mp3[a[i].x]; if(f[p]+f2[i]==ans){ add(p,i,inf); out[p]++; in[i]++; } } mp3[a[i].x]=i; } rep(i,0,n){ add(S,i,inf),add(i,T,inf); if(in[i]>out[i]){ add(SS,i,in[i]-out[i]); Sum+=in[i]-out[i]; }else{ add(i,TT,out[i]-in[i]); Sum+=out[i]-in[i]; } } } queue<int> Q; int d[N]; bool bfs(){ memset(d,0x7f,sizeof(d)); memcpy(cur,head,sizeof(head)); Q.push(SS);d[SS]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=head[u];i;i=edge[i].next)if(edge[i].cap){ int v=edge[i].to; if(d[v]>d[u]+1){ d[v]=d[u]+1;Q.push(v);} } }return d[TT]<inf; } int dfs(int u,int a){ if(u==TT || !a)return a; int flow=0,f; for(int &i=cur[u];i;i=edge[i].next)if(edge[i].cap){ int v=edge[i].to; if(d[v]==d[u]+1 && (f=dfs(v,min(a,edge[i].cap)))>0){ edge[i].cap-=f; edge[i^1].cap+=f; flow+=f; a-=f; if(!a)return flow; } } return flow; } void dinic(){ while(bfs()){ dfs(SS,inf); } } int main(){ // freopen("in.in","r",stdin); // freopen("out.out","w",stdout); scanf("%d",&n); int x,y; rep(i,1,n){ scanf("%d%d",&x,&y); a[i]=node(x,y,i); }sort(a+1,a+n+1,cmp); memset(fa,-1,sizeof(fa)); if(n==1){printf("0\n\n0\n");return 0;} dp1(); solve(); dp2(); build(); dinic(); add(T,S,inf); dinic(); printf("%d\n",edge[tot].cap); }