title
BZOJ 4200
LUOGU 2304
Description
小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面。田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤i≤n1≤i≤n) 位于坐标 (xi,yi)(xi,yi)。任意两棵树的坐标均不相同。
老司机 Mr. P 从原点 (0,0)(0,0) 驾车出发,进行若干轮行动。每一轮,Mr. P 首先选择任意一个满足以下条件的方向:
为左、右、上、左上 45∘45∘ 、右上 45∘45∘ 五个方向之一。
沿此方向前进可以到达一棵他尚未许愿过的树。
完成选择后,Mr. P 沿该方向直线前进,必须到达该方向上距离最近的尚未许愿的树,在树下许愿并继续下一轮行动。如果没有满足条件的方向可供选择,则停止行动。他会采取最优策略,在尽可能多的树下许愿。若最优策略不唯一,可以选择任意一种。
不幸的是,小园丁 Mr. S 发现由于田野土质松软,老司机 Mr. P 的小汽车在每轮行进过程中,都会在田野上留下一条车辙印,一条车辙印可看作以两棵树(或原点和一棵树)为端点的一条线段。
在 Mr. P 之后,还有很多许愿者计划驾车来田野许愿,这些许愿者都会像 Mr. P 一样任选一种最优策略行动。Mr. S 认为非左右方向(即上、左上 45∘45∘ 、右上 45∘45∘ 三个方向)的车辙印很不美观,为了维护田野的形象,他打算租用一些轧路机,在这群许愿者到来之前夯实所有“可能留下非左右方向车辙印”的地面。
“可能留下非左右方向车辙印”的地面应当是田野上的若干条线段,其中每条线段都包含在某一种最优策略的行进路线中。每台轧路机都采取满足以下三个条件的工作模式:
从原点或任意一棵树出发。
只能向上、左上 45∘45∘ 、右上 45∘45∘ 三个方向之一移动,并且只能在树下改变方向或停止。
只能经过“可能留下非左右方向车辙印”的地面,但是同一块地面可以被多台轧路机经过。
现在 Mr. P 和 Mr. S 分别向你提出了一个问题:
请给 Mr .P 指出任意一条最优路线。
请告诉 Mr. S 最少需要租用多少台轧路机。
Input
输入文件的第 1 行包含 1 个正整数 n,表示许愿树的数量。
接下来 n 行,第 i+1 行包含 2个整数 xi,yi,中间用单个空格隔开,表示第 i 棵许愿树的坐标。
Output
输出文件包括 3 行。
输出文件的第 1 行输出 1 个整数 m,表示 Mr. P 最多能在多少棵树下许愿。
输出文件的第 2 行输出 m 个整数,相邻整数之间用单个空格隔开,表示 Mr. P 应该依次在哪些树下许愿。
输出文件的第 3 行输出 1 个整数,表示 Mr. S 最少需要租用多少台轧路机。
Sample Input
6
-1 1
1 1
-2 2
0 8
0 9
0 10
Sample Output
3
2 1 3
3
explanation
最优路线 2 条可许愿 3 次:(0,0)→(1,1)→(−1,1)→(−2,2)(0,0)→(1,1)→(−1,1)→(−2,2) 或 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。 至少 3 台轧路机,路线是 (0,0)→(1,1)(0,0)→(1,1),(−1,1)→(−2,2)(−1,1)→(−2,2) 和 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。
analysis
额,去yyb大佬那里吧,我现在还解释不清有源汇上下界最小流。。
这道题的 也是够神仙的了。。
等我慢慢搞吧。。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10,maxm=maxn*20,inf=0x3f3f3f3f;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
template<typename T>inline void write(T x)
{
if (!x) { putchar('0'); return ; }
if (x<0) putchar('-'), x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48,x/=10;
while (num) putchar(ch[num--]);
}
///////////////////////////////////////////////////////////////////////////////////////////Here is flow
int ver[maxm],edge[maxm],Next[maxm],head[maxn],len=1;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len;
}
bool va[maxn][2];
int In[maxn],Out[maxn],ly[maxn],lx[maxn];
int py[maxn][1010],pr[maxn][5];
inline void build(int x,bool ty)
{
if (!x || va[x][ty]) return ;
va[x][ty]=1;
if (ty) for (int i=1; i<=ly[x]; ++i) build(py[x][i],0);
else for (int i=1; i<=lx[x]; ++i) { int y=pr[x][i]; ++Out[y],++In[x],build(y,1),add(y,x,inf); }
}
int s,t;
int dist[maxn];
inline bool bfs()
{
queue<int>q;
memset(dist,0,sizeof(dist));
q.push(s),dist[s]=1;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (edge[i] && !dist[y])
{
dist[y]=dist[x]+1;
if (y==t) return 1;
q.push(y);
}
}
}
return 0;
}
inline int get(int x,int low)
{
if (x==t) return low;
int tmp=low;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (edge[i] && dist[y]==dist[x]+1)
{
int a=get(y,min(tmp,edge[i]));
if (!a) dist[y]=0;
edge[i]-=a;
edge[i^1]+=a;
if (!(tmp-=a)) break;
}
}
return low-tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////Above is flow
///////////////////////////////////////////////////////////////////////////////////////////Here is Dp
struct Orz{int x,y,id;}a[maxn];
inline bool cmp(Orz a,Orz b)
{
return a.y<b.y || (a.y==b.y && a.x<b.x);
}
int f[maxn],d[maxn];
inline void renew(int x,int &z)
{
if (z)
{
if (f[x]<=d[z]) f[x]=d[z]+1,pr[x][ lx[x]=1 ]=z;
else if (f[x]==d[z]+1) pr[x][ ++lx[x] ]=z;
}
z=x;
}
inline void Print(int x,bool ty)//输出方案
{
if (!x) return ;
if (ty)
{
int y=py[x][1];
Print(y,0);
if (x==y) return ;
if (y<x)
{
for (int z=y-1; a[z].y==a[y].y; --z) write(a[z].id),putchar(' ');
for (int z=y+1; z<=x; ++z) write(a[z].id),putchar(' ');
}
else
{
for (int z=y+1; a[z].y==a[y].y; ++z) write(a[z].id),putchar(' ');
for (int z=y-1; z>=x; --z) write(a[z].id),putchar(' ');
}
}
else Print(pr[x][1],1),write(a[x].id),putchar(' ');
}
///////////////////////////////////////////////////////////////////////////////////////////Above is Dp
map<int,int>m1,m2,mx;
int main()
{
int n;read(n);
for (int i=1; i<=n; ++i) read(a[i].x),read(a[i].y),a[i].id=i;
sort(a+1,a+n+1,cmp);
int ans=0;
for (int i=1,lt=0; i<=n; i=lt+1)
{
while (lt<n && a[lt+1].y==a[i].y)
{
++lt;
int x=a[lt].x,y=a[lt].y;
if (x==y || x==-y || !x) f[lt]=1,pr[lt][ lx[lt]=1 ]=0;
else f[lt]=-n;
renew(lt,mx[x]),renew(lt,m1[x+y]),renew(lt,m2[x-y]);
}
int w;
for (int j=i; j<=lt; ++j)
{
w=f[j];
py[j][ ly[j]=1 ]=j;
for (int k=i; k<=j-1; ++k)
if (f[k]+j-i>w) w=f[k]+j-i, py[j][ ly[j]=1 ]=k;
else if (f[k]+j-i==w) py[j][ ++ly[j] ]=k;
d[j]=w;
}
for (int j=lt; j>=i; --j)
{
w=d[j];
for (int k=j+1; k<=lt; ++k)
if (f[k]+lt-j>w) w=f[k]+lt-j, py[j][ ly[j]=1 ]=k;
else if (f[k]+lt-j==w) py[j][ ++ly[j] ]=k;
d[j]=w;
ans=max(ans,w);
}
}
write(ans),puts("");
for (int i=1; i<=n; ++i)
if (d[i]==ans) { Print(i,1),puts(""); break; }
s=n+1,t=n+2;
for (int i=1; i<=n; ++i)
if (d[i]==ans) build(i,1);
int sum=0;
for (int i=0; i<=n; ++i)
if (In[i]>Out[i]) add(s,i,In[i]-Out[i]),sum+=In[i]-Out[i];
else add(i,t,Out[i]-In[i]);
int res=0;
while (bfs()) res+=get(s,inf);
write(sum-res),puts("");
return 0;
}