您的位置:首页 > 其它

4200: [Noi2015]小园丁与老司机 DP+有源汇上下界最小流

2016-03-08 08:10 393 查看
终于做完了NOI2015的所有题目qwq

码农题+细节题啊。。

首先正反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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: