4200: [Noi2015]小园丁与老司机 DP+有源汇上下界最小流
2016-03-08 08:10
393 查看
终于做完了NOI2015的所有题目qwq
码农题+细节题啊。。
首先正反DP求出所有的最优路径,同一行转移一定要写对。。正反的时候是不一样的,然后根据最优路径建图跑最小流就行了。。
成功在UOJ垫了一波大底。。
码农题+细节题啊。。
首先正反DP求出所有的最优路径,同一行转移一定要写对。。正反的时候是不一样的,然后根据最优路径建图跑最小流就行了。。
成功在UOJ垫了一波大底。。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> #define inf 1000000007 #define N 50050 #define M 2000020 using namespace std; int n,cnt=1,ans,tot,pos,S,T,SS,TT; int head ,dis ,q ,dp ,mx ,du ,f ,cur ,g ,from ,stack ,seq ; struct node {int x,y,id;} a ; int next[M],list[M],key[M]; bool tag ; map<int,int> mp1,mp2,mp3; inline int read() { int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } inline bool operator<(node a,node b) { return a.y==b.y?a.x<b.x:a.y<b.y; } inline void insert(int x,int y,int z) { next[++cnt]=head[x]; head[x]=cnt; list[cnt]=y; key[cnt]=z; } inline void DP1() { for (int i=1;i<=n;i++) dp[i]=mx[i]=-inf; dp[0]=0; for (int i=0,t=0;i<=n;i=++t) { while (t<n&&a[t+1].y==a[t].y) t++; for (int j=i;j<=t;j++) { if (mp1.find(a[j].x+a[j].y)!=mp1.end()) { int p=mp1[a[j].x+a[j].y]; if (dp[p]+1>dp[j]) dp[j]=dp[p]+1,g[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 (dp[p]+1>dp[j]) dp[j]=dp[p]+1,g[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 (dp[p]+1>dp[j]) dp[j]=dp[p]+1,g[j]=p; } mp3[a[j].x]=j; } int now=-1; for (int j=i+1;j<=t;j++) { if (now==-1||dp[j-1]>dp[now]) now=j-1; if (dp[now]+j-i>mx[j]) mx[j]=dp[now]+j-i,from[j]=now; } now=-1; for (int j=t-1;j>=i;j--) { if (now==-1||dp[j+1]>dp[now]) now=j+1; if (dp[now]+t-j>mx[j]) mx[j]=dp[now]+t-j,from[j]=now; } for (int j=i;j<=t;j++) if (mx[j]>dp[j]) dp[j]=mx[j],tag[j]=1; } pos=0; for (int i=1;i<=n;i++) if (dp[i]>dp[pos]) pos=i; ans=dp[pos]; printf("%d\n",ans); } inline void DP2() { mp1.clear(); mp2.clear(); mp3.clear(); for (int i=1;i<=n;i++) if (dp[i]==ans) f[i]=1; else f[i]=0; for (int i=1;i<=n;i++) mx[i]=-inf; for (int i=n,t=n;~i;i=--t) { while (t&&a[t-1].y==a[t].y) t--; for (int j=t;j<=i;j++) { 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; } 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; } 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; } mp3[a[j].x]=j; } int now=-1; for (int j=t+1;j<=i;j++) { if (now==-1||f[j-1]+i-j+1>f[now]+i-now) now=j-1; if (f[now]+i-now>mx[j]) mx[j]=f[now]+i-now; } now=-1; for (int j=i-1;j>=t;j--) { if (now==-1||f[j+1]+j+1-t>f[now]+now-t) now=j+1; if (f[now]+now-t>mx[j]) mx[j]=f[now]+now-t; } for (int j=t;j<=i;j++) if (mx[j]>f[j]) f[j]=mx[j]; } } inline int findl(int x) { int l=1,r=n,ans; while (l<=r) { int mid=l+r>>1; if (a[mid].y>=x) ans=mid,r=mid-1; else l=mid+1; } return ans; } inline int findr(int x) { int l=1,r=n,ans; while (l<=r) { int mid=l+r>>1; if (a[mid].y<=x) ans=mid,l=mid+1; else r=mid-1; } return ans; } inline void print(int x,int y) { int l=findl(a[x].y),r=findr(a[x].y); if (x<y) { for (int i=x;i>=l;i--) seq[++tot]=i; for (int i=x+1;i<=y;i++) seq[++tot]=i; } else { for (int i=x;i<=r;i++) seq[++tot]=i; for (int i=x-1;i>=y;i--) seq[++tot]=i; } } inline void solve() { int top=0; tot=0; while (pos) if (tag[pos]) stack[++top]=pos,stack[++top]=from[pos],pos=g[from[pos]]; else stack[++top]=pos,pos=g[pos]; while (top) if (top>1&&a[stack[top]].y==a[stack[top-1]].y) print(stack[top],stack[top-1]),top-=2; else seq[++tot]=stack[top--]; for (int i=1;i<=tot;i++) printf("%d ",a[seq[i]].id); puts(""); } inline bool BFS() { int t=0,w=1,x; memset(dis,-1,sizeof(dis)); q[1]=SS; dis[SS]=1; while (t<w) { x=q[++t]; for (int i=head[x];i;i=next[i]) if (key[i]&&dis[list[i]]==-1) dis[q[++w]=list[i]]=dis[x]+1; } return dis[TT]!=-1; } int find(int x,int flow) { if (x==TT) return flow; int w,used=0; for (int i=cur[x];i;i=next[i]) if (key[i]&&dis[list[i]]==dis[x]+1) { w=find(list[i],min(key[i],flow-used)); key[i]-=w; key[i^1]+=w; used+=w; if (key[i]) cur[x]=i; if (used==flow) return used; } if (!used) dis[x]=-1; return used; } inline void dinic() { int tmp=0; while (BFS()) { for (int i=0;i<=TT;i++) cur[i]=head[i]; tmp+=find(SS,inf); } } inline void build() { S=n+1; T=n+2; SS=T+1; TT=T+2; mp1.clear(); mp2.clear(); mp3.clear(); for (int i=n;~i;i--) { if (mp1.find(a[i].x+a[i].y)!=mp1.end()) { int p=mp1[a[i].x+a[i].y]; if (dp[i]+f[p]==ans) insert(i,p,inf),insert(p,i,0),du[i]--,du[p]++; } 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 (dp[i]+f[p]==ans) insert(i,p,inf),insert(p,i,0),du[i]--,du[p]++; } mp2[a[i].x-a[i].y]=i; if (mp3.find(a[i].x)!=mp3.end()) { int p=mp3[a[i].x]; if (dp[i]+f[p]==ans) insert(i,p,inf),insert(p,i,0),du[i]--,du[p]++; } mp3[a[i].x]=i; } for (int i=0;i<=n;i++) insert(S,i,inf),insert(i,S,0),insert(i,T,inf),insert(T,i,0); for (int i=0;i<=n;i++) if (du[i]>0) insert(SS,i,du[i]),insert(i,SS,0); else if (du[i]<0) insert(i,TT,-du[i]),insert(TT,i,0); } int main() { n=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].id=i; sort(a+1,a+n+1); DP1(); DP2(); solve(); build(); dinic(); insert(T,S,inf); insert(S,T,0); dinic(); cout << key[cnt] << endl; return 0; }
相关文章推荐
- java,作业张三李四,运用类的继承
- Ubuntu 16.04 为更好支持容器化而采用 ZFS
- 线段树——I hate it
- 程序中写数据到文件
- 互联网面试总结(三) : 算法
- 《数据结构》顺序栈
- ATEN宏正盛装出席Infocomm China 2016
- 互联网面试总结(二) : 概述题
- HTML 5 视频使用
- 正则表达式
- 前端性能优化--能用css的地方尽量不要用js
- [leetcode] 167. Two Sum II - Input array is sorted 解题报告
- 软件第二次作业
- 作业
- oracle GROUPING函数
- Linux用户和用户组基本概念
- andriod VideoView
- rcnn学习笔记:Rich feature hierarchies for accurate object detection and semantic segmentation
- HDU 2105 The Center of Gravity (水题)
- huffman树_优先权队列