NOI2015 小园丁和老司机

题目链接

洛谷的,有点不清楚。

建议去UOJ上或LOJ切了再搬运。

luogu

UOJ

LOJ

sol

老司机是一个显然的\(dp\)

发现是个\(DAG\),可以愉快的按\(y\)坐标排序转移。

发现五个移动不好算,那么设\(g[i]\)表示从\(i\)点开始前往\(y\)坐标比\(i\)大的点的最多到的许愿树个数,\(f[i]\)表示从\(i\)进入\(y\)坐标能够最多到的许愿树个数。

先算这一层所有的\(g\),再算\(f\)。分两种情况,入点在出点右边或左边,只要从前往后\(dp\)一次,从后往前\(dp\)一次就\(ok\)了。

\(g\)的话维护三个桶,分别代表\(x+y\),\(x-y\),\(x\)的桶,用\(f\)转移\(g\)

因为如果\(i<j,y_i==y_j\),从\(i\)点进\(j\)点出可以先往左走,再往右走到\(j\)离开,所以算的时候贡献是\(y\)坐标为\(y_i\)的点的个数减去\(j\)和它右边的点的个数,那么我们可以一开始减掉,最后算答案的时候加上\(y\)坐标为\(y_i\)的点的个数。这显然是个前缀或后缀\(max\)的优化\(dp\)

那么我们得到了\(20\ pts\ QAQ\)

\(40\)分的话也好做,\(dfs\)一条路出来,你怎么转移的就倒过来怎么找路径,具体可以看代码。

\(100\)分不难,按\(40\)分的思路去找所有的边,只是不\(dfs\)而是遍历每个可能出现的点。

然后就是个很裸的上下界最小流了。

\(litble\)说直接写会\(TLE\),所以我就没写最裸的,加了个优化。

因为你肯定有解,并且\(S\)\(T\)到每个点都有\(inf\)的边,所以我们不管它们,直接建超级源汇连原图,跑出来最大流就是图本生可以减少的流量。

减掉就\(ok\)了。

不算网络流模板这道题还挺短的\(QAQ\)

#include<map>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#define gt getchar()
#define ll long long
#define Set(p,v) memset(p,v,sizeof(p))
#define Cpy(p,v) memcpy(p,v,sizeof(p))
inline int in()
{
	int k=0,p=1;char ch=gt;
	while(!isdigit(ch)&&ch!='-')ch=gt;
	if(ch=='-')p=0,ch=gt;
	while(isdigit(ch))k=k*10+ch-'0',ch=gt;
	return p?k:-k;
}
inline int min(const int &a,const int &b){return a<b?a:b;}
inline int max(const int &a,const int &b){return a>b?a:b;}
const int inf=0x7fffffff;
class Graph
{
private:
	static const int N=400005,M=1000005;
	int s,t;
	int dis[N];
	int	pre[N],pr[N],o[N],cur[N];
	int head[N],nxt[M],to[M],cap[M];double w[M];
public:
	int n,cnt;
	inline void init(int nn,int ss,int tt){n=nn,s=ss,t=tt;cnt=-1;Set(head,-1);}
	inline void add_Edge(int u,int v,int cc,int ww){to[++cnt]=v,cap[cnt]=cc,w[cnt]=ww,nxt[cnt]=head[u],head[u]=cnt;}
	inline void add(int u,int v,int cc,int ww=0){add_Edge(u,v,cc,ww),add_Edge(v,u,0,-ww);}
	int dfs(int u,int dist)
		{
			if(u==t)return dist;
			for(int &i=cur[u];~i;i=nxt[i])
			{
				if(dis[to[i]]==dis[u]+1&&cap[i]!=0)
				{
					int d=dfs(to[i],min(dist,cap[i]));
					if(d>0){cap[i]-=d;cap[i^1]+=d;return d;}
				}
			}
			return 0;
		}
	int bfs()
		{
			std::queue<int>Q;Set(dis,0);
			Q.push(s);dis[s]=1;
			while(!Q.empty())
			{
				int u=Q.front();Q.pop();
				for(int i=head[u];~i;i=nxt[i])
				{
					if(cap[i]>0&&dis[to[i]]==0)
					{
						dis[to[i]]=dis[u]+1;
						Q.push(to[i]);
					}
				}
			}
			return dis[t]>0;
		}
	int dinic()
		{
			int res=0,d;
			while(bfs()){Cpy(cur,head);while((d=dfs(s,inf)))res+=d;}
			return res;
		}
	int spfa()
		{
			//实数流的时候务必用for给dis赋值
			std::queue<int>Q;Set(dis,0x3f);Set(pr,0);Set(o,0);Set(pre,0);
			dis[s]=0;Q.push(s);o[s]=1;
			while(!Q.empty())
			{
				int u=Q.front();Q.pop();o[u]=0;
				for(int i=head[u];~i;i=nxt[i])
					if(cap[i]>0&&dis[to[i]]>dis[u]+w[i])
					{
						dis[to[i]]=dis[u]+w[i];
						pr[to[i]]=i;pre[to[i]]=u;
						if(!o[to[i]])o[to[i]]=1,Q.push(to[i]);
					}
			}
			return pre[t]!=0;
		}
	void fyl(int &ans,int &hh)
		{
			ans=hh=0;
			while(spfa())
			{
				int d=inf;
				for(int i=t;i!=s;i=pre[i])d=min(d,cap[pr[i]]);hh+=dis[t]*d;ans+=d;
				for(int i=t;i!=s;i=pre[i])cap[pr[i]]-=d,cap[pr[i]^1]+=d;
			}
		}
	int fyl()
		{
			int hh=0;
			while(spfa())
			{
				int d=inf;
				for(int i=t;i!=s;i=pre[i])d=min(d,cap[pr[i]]);hh+=dis[t]*d;
				for(int i=t;i!=s;i=pre[i])cap[pr[i]]-=d,cap[pr[i]^1]+=d;
			}
			return hh;
		}
}cx;

typedef std::pair<int,int> P;
#define mk std::make_pair
#define fr first
#define sc second
const int N=50005;
int n,tot;P E[N*20];
struct point{int x,y,id;}a[N];
inline bool cmpx(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
inline bool cmpy(point a,point b){return a.y==b.y?a.x<b.x:a.y<b.y;}
inline bool cmpi(point a,point b){return a.id<b.id;}
inline void cmax(int &x,int y,int *a,int &c,int b){if(x<y)x=y,a[(c=1)-1]=b;else if(x==y)a[c++]=b;}
inline void cmax(int &x,int y){if(x<y)x=y;}
inline void Push(int x,int y){E[++tot]=mk(x,y);}

namespace w1
{
	using std::map;
	map<int,int>t1,t2,t3,mp[N];
	int f[N],g[N],pre[N][3],L[N],R[N],TT,o[N],cnt[N];
	inline int calc(int u,int k)
	{
		if(u==k)return g[k];
		if(u<k)return g[k]+k-L[k];
		else return g[k]+R[k]-k;
	}
	void dfs(int val,int u)//求一组最优方案
	{
		if(u==-1)return;
		if(u!=1)printf("%d ",a[u].id);
		int l=L[u],r=R[u];
		for(int i=l;i<=r;++i)
			if(calc(u,i)==val)
			{
				if(u==i)return dfs(g[u]-1,pre[u][0]);
				if(u<i)for(int j=u-1;j>=l;--j)printf("%d ",a[j].id);
				else for(int j=u+1;j<=r;++j)printf("%d ",a[j].id);
				if(u<i)for(int j=u+1;j<=i;++j)printf("%d ",a[j].id);
				else for(int j=u-1;j>=i;--j)printf("%d ",a[j].id);
				return dfs(g[i]-1,pre[i][0]);
			}
	}
	void Dfs(int val,int u)//求所有边
	{
		if(u==-1||o[u])return;
		int l=L[u],r=R[u];o[u]=1;
		for(int i=l;i<=r;++i)
			if(calc(u,i)==val)
				for(int k=0;k<cnt[i];++k)
					if(pre[i][k]&&pre[i][k]!=-1)
					{
						if(mp[i].find(k)==mp[i].end())Push(i,pre[i][k]),mp[i][k]=1;
						if(!o[pre[i][k]])Dfs(g[i]-1,pre[i][k]);
					}
	}
	void solve()
	{
		a[++n]=(point){0,0,0};std::sort(a+1,a+n+1,cmpy);
		for(int i=n,j;i>=1;i=j-1)
		{
			for(j=i;j>1&&a[j-1].y==a[i].y;--j);
			for(int k=j;k<=i;++k)L[k]=j,R[k]=i;
			for(int k=j;k<=i;++k)
			{
				int x=a[k].x,y=a[k].y;g[k]=1;pre[k][cnt[k]=0]=-1;
				if(t1.find(x+y)!=t1.end())cmax(g[k],f[t1[x+y]]+1,pre[k],cnt[k],t1[x+y]);
				if(t2.find(x-y)!=t2.end())cmax(g[k],f[t2[x-y]]+1,pre[k],cnt[k],t2[x-y]);
				if(t3.find( x )!=t3.end())cmax(g[k],f[t3[ x ]]+1,pre[k],cnt[k],t3[ x ]);
				t1[x+y]=t2[x-y]=t3[x]=k;
			}
			for(int k=j,mx=-1e9;k<=i;++k)
				cmax(f[k],g[k]),cmax(f[k],mx+i-j),cmax(mx,g[k]-k+j);
			for(int k=i,mx=-1e9;k>=j;--k)
				cmax(f[k],g[k]),cmax(f[k],mx+i-j),cmax(mx,g[k]-i+k);
		}
		printf("%d\n",f[1]-1);dfs(f[1],1);puts("");Dfs(f[1],1);
	}
}

namespace w2
{
	int du[N];
	void solve()
	{
		int t=n+1,s=0,ans=0;cx.init(t+1,s,t);
		for(int i=1;i<=tot;++i)
			--du[E[i].fr],++du[E[i].sc],cx.add(E[i].fr,E[i].sc,inf);
		for(int i=1;i<=n;++i)
			if(du[i]>0)cx.add(s,i,du[i]),ans+=du[i];
			else if(du[i]<0)cx.add(i,t,-du[i]);
		printf("%d\n",ans-cx.dinic());
	}
}
int main()
{
	n=in();
	for(int i=1;i<=n;++i)a[i].x=in(),a[i].y=in(),a[i].id=i;
	w1::solve();w2::solve();
	return 0;
}

posted @ 2019-02-23 11:22  Cgod  阅读(281)  评论(0编辑  收藏  举报