这题。。。连想带写一整天gg
首先第一问,是个dp,先把所有点按y为第一关键字,x为第二关键字,从小到大排序,我们把所有y相等的点叫做一层。则一层一层的dp,隔层之间转移可以直接O(1)转移(每个点只能从最多三个点上来),层内可以 O(n2) O ( n 2 ) 转移(如果不要求记录路径的话,可以做到O(n))。同层怎么转移呢?首先我们有刚进入这一层时各个点的最优值,现在我们要求出从这一层出去的每个点的最优值,可以发现如果我们要求从i出去的最优值,则我们只需枚举一个进入这层的j点,就可以转移了。(i左边的点随便选一个进入,都可以先走到最左端,然后再走回i,所以可以遍历i左边的所有点,右边同理,别忘了还有自己。)然后我们输出一条合法路径就好了。
现在求第二问,就是从dp值为ans的所有点遍历所有的最优决策点,根据决策建边。然后要求用最少的路径数覆盖所有边。可以直接用有上下界的最小流解决,做法见:bzoj2502。
还可以有个小优化:跑最小流时第二遍的结果一定是满流的,所以可以只跑第一遍,然后用满流-第一遍的最大流就是答案。至于路径怎么记录,可以详见代码。
#include
#include
#include
#include
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,lsy[N],lsx[N],ls1[N],ls2[N],ny=0,nx=0,n1=0,n2=0,last1[N],last2[N],lastx[N];
int yl[N],yr[N],path[N][4],dp[N],h[N],num=1,s=50001,t=50002,T=50003,S=50004,out[N];
int cur[N],lev[N],in[N];
vector<int>best[N];
bool vis[N];
struct Point{
int x,y,id,k1,k2;
}p[N];
struct edge{
int to,next,val;
}data[N*20];
inline bool cmp(Point x,Point y){return x.y==y.y?x.xinline int abs(int x){return x<0?-x:x;}
inline void add(int x,int y,int val){
data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=0;
}
inline void work(int l,int r){
int mx[5100],mx1[5100],tmp[5100];
memset(mx,0,sizeof(mx));memset(mx1,0,sizeof(mx1));
for(int i=l;i<=r;++i) tmp[i-l+1]=dp[i];
for(int i=l;i<=r;++i) mx[i-l+1]=max(dp[i],mx[i-l+1-1]);
for(int i=r;i>=l;--i) mx1[i-l+1]=max(dp[i],mx1[i-l+1+1]);
for(int i=l;i<=r;++i){
if(mx[i-l+1-1]!=0) dp[i]=max(dp[i],i-l+mx[i-l+1-1]);
if(mx1[i-l+1+1]!=0) dp[i]=max(dp[i],r-i+mx1[i-l+1+1]);
}for(int i=l;i<=r;++i){
for(int j=l;jif(tmp[j-l+1]!=-1&&i-l+tmp[j-l+1]==dp[i]) best[i].push_back(j);
for(int j=i+1;j<=r;++j)
if(tmp[j-l+1]!=-1&&r-i+tmp[j-l+1]==dp[i]) best[i].push_back(j);
if(tmp[i-l+1]!=-1&&tmp[i-l+1]==dp[i]) best[i].push_back(i);
}
}
inline void dfs(int x){
if(x==0) return;
int y=best[x][0];
dfs(path[y][1]);
if(y==x){printf("%d ",p[x].id);return;}
if(yfor(int i=y;i>=yl[p[x].y];--i) printf("%d ",p[i].id);
for(int i=y+1;i<=x;++i) printf("%d ",p[i].id);return;
}
for(int i=y;i<=yr[p[x].y];++i) printf("%d ",p[i].id);
for(int i=y-1;i>=x;--i) printf("%d ",p[i].id);return;
}
inline void dfs1(int x){
if(x==0) return;
for(int i=0;iint y=best[x][i];if(vis[y]) continue;vis[y]=1;
for(int i=1;i<=path[y][0];++i){
add(path[y][i],y,inf);out[path[y][i]]++;
in[y]++;in[path[y][i]]--;dfs1(path[y][i]);
}
}
}
inline bool bfs(){
queue<int>q;memset(lev,0,sizeof(lev));
lev[S]=1;q.push(S);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]||!data[i].val) continue;
lev[y]=lev[x]+1;q.push(y);
}
}return lev[T];
}
inline int dinic(int x,int low){
if(x==T) return low;int tmp=low;
for(int &i=cur[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]!=lev[x]+1||!data[i].val) continue;
int res=dinic(y,min(tmp,data[i].val));
if(!res) lev[y]=0;else tmp-=res,data[i].val-=res,data[i^1].val+=res;
if(!tmp) return low;
}return low-tmp;
}
int main(){
// freopen("a2.in","r",stdin);
// freopen("a.out","w",stdout);
n=read();memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;++i){
p[i].x=read(),p[i].y=read(),p[i].id=i;lsy[i]=p[i].y;lsx[i]=p[i].x;
ls1[i]=p[i].k1=p[i].y-p[i].x;ls2[i]=p[i].k2=p[i].y+p[i].x;
}sort(lsy,lsy+n+1);sort(ls1,ls1+n+1);sort(ls2,ls2+n+1);sort(lsx,lsx+n+1);
ny=unique(lsy,lsy+n+1)-lsy-1;nx=unique(lsx,lsx+n+1)-lsx-1;
n1=unique(ls1,ls1+n+1)-ls1-1;n2=unique(ls2,ls2+n+1)-ls2-1;
for(int i=0;i<=n;++i){
p[i].k1=lower_bound(ls1,ls1+n1+1,p[i].k1)-ls1;
p[i].k2=lower_bound(ls2,ls2+n2+1,p[i].k2)-ls2;
p[i].y=lower_bound(lsy,lsy+ny+1,p[i].y)-lsy;
p[i].x=lower_bound(lsx,lsx+nx+1,p[i].x)-lsx;
}sort(p+1,p+n+1,cmp);int last=1;memset(last1,-1,sizeof(last1));
memset(last2,-1,sizeof(last2));memset(lastx,-1,sizeof(lastx));
last1[p[0].k1]=last2[p[0].k2]=lastx[p[0].x]=0;
memset(path,-1,sizeof(path));dp[0]=0;
for(int i=1;i<=n;++i){
while(last<=n&&p[last].y==p[i].y){
Point &a=p[last];int tot=0;
if(last1[a.k1]!=-1&&dp[last1[a.k1]]!=-1){
if(dp[last1[a.k1]]+1==dp[last]) path[last][++tot]=last1[a.k1];
if(dp[last1[a.k1]]+1>dp[last]) dp[last]=dp[last1[a.k1]]+1,tot=0,path[last][++tot]=last1[a.k1];
}last1[a.k1]=last;
if(last2[a.k2]!=-1&&dp[last2[a.k2]]!=-1){
if(dp[last2[a.k2]]+1==dp[last]) path[last][++tot]=last2[a.k2];
if(dp[last2[a.k2]]+1>dp[last]) dp[last]=dp[last2[a.k2]]+1,tot=0,path[last][++tot]=last2[a.k2];
}last2[a.k2]=last;
if(lastx[a.x]!=-1&&dp[lastx[a.x]]!=-1){
if(dp[lastx[a.x]]+1==dp[last]) path[last][++tot]=lastx[a.x];
if(dp[lastx[a.x]]+1>dp[last]) dp[last]=dp[lastx[a.x]]+1,tot=0,path[last][++tot]=lastx[a.x];
}lastx[a.x]=last;path[last][0]=tot;++last;
}last--;yl[p[i].y]=i;yr[p[i].y]=last;
work(i,last);i=last;last++;
}int ans=0,tot=0;
for(int i=1;i<=n;++i) if(dp[i]>dp[ans]) ans=i;
printf("%d\n",dp[ans]);dfs(ans);puts("");
for(int i=1;i<=n;++i) if(dp[i]==dp[ans])dfs1(i);ans=0;
for(int i=0;i<=n;++i){
add(s,i,inf);if(!out[i]) add(i,t,inf);
if(in[i]>0) add(S,i,in[i]),tot+=in[i];
if(in[i]<0) add(i,T,-in[i]);
}while(bfs()){memcpy(cur,h,sizeof(cur));ans+=dinic(S,inf);}
printf("%d\n",tot-ans);
return 0;
}
6.26UPD:
#include
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,nn,to[N][3],aa[N],lst[N],b[N],f[N],path[N][4],g[N],best[N],id[N];//f[i],到点i的最多经过点数
int ss,tt,S=0,T,cur[N],lev[N],in[N],h[N],num=1;bool vis[N];
struct point{
int x,y,id;
friend bool operator<(point a,point b){return a.y==b.y?a.xvector<int>path1[N],anss;
struct edge{
int to,next,val;
}data[N*12];
inline void add(int x,int y,int val){
data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=0;
}
inline void solve(int mm){
int mx=-inf;best[0]=0;
for(int i=1;i<=mm;++i){
if(mx+i-1>g[b[i]]){
g[b[i]]=mx+i-1,path1[b[i]].clear();
for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
}else if(mx+i-1==g[b[i]]) for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
if(f[b[i]]>mx) mx=f[b[i]],best[best[0]=1]=b[i];
else if(f[b[i]]==mx) best[++best[0]]=b[i];
}mx=-inf;best[0]=0;
for(int i=mm;i>=1;--i){
if(mx+mm-i>g[b[i]]){
g[b[i]]=mx+mm-i,path1[b[i]].clear();
for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
}else if(mx+mm-i==g[b[i]]) for(int j=1;j<=best[0];++j) path1[b[i]].push_back(best[j]);
if(f[b[i]]>mx) mx=f[b[i]],best[best[0]=1]=b[i];
else if(f[b[i]]==mx) best[++best[0]]=b[i];
}for(int i=1;i<=mm;++i){
if(f[b[i]]>g[b[i]]){
g[b[i]]=f[b[i]],path1[b[i]].clear();path1[b[i]].push_back(b[i]);
}else if(f[b[i]]==g[b[i]]) path1[b[i]].push_back(b[i]);
}for(int i=1;i<=mm;++i) f[b[i]]=g[b[i]];
}
inline void dfs(int x){
if(x==1) return;
anss.push_back(x);
int y=path1[x][0];
if(id[y]int xx=id[x]-1;
while(xx>id[y]) anss.push_back(a[xx].id),--xx;
xx=id[y];
while(a[xx].y==a[id[x]].y) --xx;++xx;
while(xxif(id[y]>id[x]){
int xx=id[x]+1;
while(xxwhile(a[xx].y==a[id[x]].y) ++xx;--xx;
while(xx>id[y]) anss.push_back(a[xx].id),--xx;
}if(x!=y) anss.push_back(y);dfs(path[y][1]);
}
inline void dfs1(int x){
if(x==1) return;
for(int i=0;iint y=path1[x][i];if(vis[y]) continue;vis[y]=1;
for(int j=1;j<=path[y][0];++j) in[y]++,in[path[y][j]]--,add(path[y][j],y,inf),dfs1(path[y][j]);
}
}
inline bool bfs(){
queue<int>q;memset(lev,0,sizeof(lev));
q.push(S);lev[S]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]||!data[i].val) continue;
lev[y]=lev[x]+1;if(y==T) return 1;q.push(y);
}
}return 0;
}
inline int dinic(int x,int low){
if(x==T) return low;int tmp=low;
for(int &i=cur[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]!=lev[x]+1||!data[i].val) continue;
int res=dinic(y,min(tmp,data[i].val));
if(!res) lev[y]=0;else tmp-=res,data[i].val-=res,data[i^1].val+=res;
if(!tmp) return low;
}return low-tmp;
}
int main(){
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
n=read()+1;a[1].id=1;a[1].x=0;a[1].y=0;memset(f,-inf,sizeof(f));memset(g,-inf,sizeof(g));
for(int i=2;i<=n;++i) a[i].id=i,a[i].x=read(),a[i].y=read();f[1]=0;g[1]=0;
sort(a+1,a+n+1);for(int i=1;i<=n;++i) id[a[i].id]=i;
for(int i=1;i<=n;++i) aa[i]=a[i].x;
sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;
for(int i=1;i<=n;++i){
int x=lower_bound(aa+1,aa+nn+1,a[i].x)-aa;
to[lst[x]][0]=a[i].id;lst[x]=a[i].id;
}for(int i=1;i<=n;++i) aa[i]=a[i].x+a[i].y;
sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;memset(lst,0,sizeof(lst));
for(int i=1;i<=n;++i){
int x=lower_bound(aa+1,aa+nn+1,a[i].x+a[i].y)-aa;
to[lst[x]][1]=a[i].id;lst[x]=a[i].id;
}for(int i=1;i<=n;++i) aa[i]=a[i].x-a[i].y;
sort(aa+1,aa+n+1);nn=unique(aa+1,aa+n+1)-aa-1;memset(lst,0,sizeof(lst));
for(int i=1;i<=n;++i){
int x=lower_bound(aa+1,aa+nn+1,a[i].x-a[i].y)-aa;
to[lst[x]][2]=a[i].id;lst[x]=a[i].id;
}for(int i=1,j;i<=n;i=j+1){
j=i;while(j<=n&&a[j].y==a[i].y) ++j;--j;
for(int k=1;k<=j-i+1;++k) b[k]=a[i+k-1].id;solve(j-i+1);
for(int k=i;k<=j;++k){
int x=a[k].id;
for(int ii=0;ii<3;++ii){
int y=to[x][ii];if(!y) continue;
if(f[x]+1>f[y]) f[y]=f[x]+1,path[y][path[y][0]=1]=x;
else if(f[x]+1==f[y]) path[y][++path[y][0]]=x;
}
}
}int ans=0;for(int i=1;i<=n;++i) ans=max(ans,f[i]);
printf("%d\n",ans);
for(int i=1;i<=n;++i) if(f[i]==ans){dfs(i);break;}
reverse(anss.begin(),anss.end());
for(int i=0;iprintf("%d ",anss[i]-1);puts("");
for(int i=1;i<=n;++i) if(f[i]==ans) dfs1(i);ss=n+1;tt=n+2;T=n+3;int tot=0;
for(int i=1;i<=n;++i){
add(ss,i,inf),add(i,tt,inf);
if(in[i]>0) add(S,i,in[i]),tot+=in[i];
else add(i,T,-in[i]);
}ans=0;while(bfs()){memcpy(cur,h,sizeof(h));ans+=dinic(0,inf);}
printf("%d\n",tot-ans);
return 0;
}