ARC122F
太庙了太庙了
首先我们可以跑一遍单调栈使得栈中元素横坐标单增纵坐标单减。
先考虑 \(K=1\) 的情况
考虑将B向右移,将R向下移动使得符合条件,则向下移有1费,向右移有1费。
也就转化成了(假设 \(X,Y\) 有序):
- \(X_i\to X_{i+1}\ w=dis_x(i,i+1)\)
- \(Y_{i+1}\to Y_i\ w=dis_y(i,i+1)\)
- \(Y_i\to X_i\ w=0[i\ is\ blue ]\)
其中第三个可以代表一个断点:一开始一直向下移动,从这里开始向右移动。
答案即是求 \(Y_n\) 到 \(X_n\)的最短路。
那么现在 \(K>1\) 了,也就是说我们可以有 \(K\) 个断点了。其实也就是多了一个边:
- \(X_i\to Y_{i+1}\ w=0[i\ is\ red]\)
限制每个蓝色石头只能用一次所以第三个边流量是1,其他边流量是inf。
那么我们就可以跑一个费用流求解了。
Code
听说Atcoder卡spfa于是去学了一下dij费用流,跑的还挺快的。
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
namespace EMT{
typedef long long ll;typedef double db;
#define pf printf
#define F(i,a,b) for(int i=a;i<=b;i++)
#define D(i,a,b) for(int i=a;i>=b;i--)
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;}
inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
const int N=1e6+10,infi=0x3f3f3f3f;const ll infl=0x3f3f3f3f3f3f3f3f;
int n,m,K,sx[N],sy[N],co=1,head[N],pe[N];ll dis[N],flow[N],h[N];bool vis[N];
struct pt{int x,y;friend bool operator <(pt a,pt b){return a.x==b.x?a.y<b.y:a.x<b.x;}}p[N];
struct dp{int x;ll v;friend bool operator <(dp a,dp b){return a.v>b.v;}};
struct node{int next,to,w1,w2;}e[N*10];std::priority_queue<dp>q;
inline void add(int next,int to,int w1,int w2){e[++co]={head[next],to,w1,w2},head[next]=co;}
inline void ins(int next,int to,int w1,int w2){add(next,to,w1,w2),add(to,next,0,-w2);}
inline void dij(int S,int T,int n){
memset(dis,0x3f,sizeof(ll)*(n+1));dis[S]=0;
memset(vis,0,sizeof(bool)*(n+1));flow[S]=infi;
q.push({S,0});
while(!q.empty()){
int x=q.top().x;q.pop();if(vis[x])continue;vis[x]=1;
for(int i(head[x]),j(e[i].to);i;j=e[i=e[i].next].to)if(e[i].w1){
if(dis[j]>dis[x]+h[x]-h[j]+e[i].w2){
dis[j]=dis[x]+h[x]-h[j]+e[i].w2;
pe[j]=i;flow[j]=min(flow[x],e[i].w1);
q.push({j,dis[j]});
}
}
}
}
inline ll EK(int S,int T,int n){
dij(S,T,n);
F(i,1,n)h[i]+=dis[i];
ll ans=h[T];
for(int i=T;i^S;i=e[pe[i]^1].to)
e[pe[i]].w1--,e[pe[i]^1].w1++;
return ans;
}
inline short main(){
n=read(),m=read(),K=read();
F(i,1,n+m)sx[i]=p[i].x=read(),sy[i]=p[i].y=read();
std::sort(sx+1,sx+n+m+1),std::sort(sy+1,sy+n+m+1);
sx[0]=std::unique(sx+1,sx+n+m+1)-sx-1;
sy[0]=std::unique(sy+1,sy+n+m+1)-sy-1;
F(i,2,sx[0])ins(i-1,i,infi,sx[i]-sx[i-1]),ins(i,i-1,infi,0);
F(i,2,sy[0])ins(i+sx[0],i+sx[0]-1,infi,sy[i]-sy[i-1]),ins(i+sx[0]-1,i+sx[0],infi,0);
static pt s[N];int top=0;
std::sort(p+1,p+n+1);
F(i,1,n){
while(top&&s[top].y<=p[i].y)top--;
s[++top]=p[i];
}
F(i,1,top)s[i].x=std::lower_bound(sx+1,sx+sx[0]+1,s[i].x)-sx,
s[i].y=std::lower_bound(sy+1,sy+sy[0]+1,s[i].y)-sy;
F(i,2,top)ins(s[i-1].x,sx[0]+s[i].y,infi,0);
F(i,n+1,n+m){
p[i].x=std::lower_bound(sx+1,sx+sx[0]+1,p[i].x)-sx;
p[i].y=std::lower_bound(sy+1,sy+sy[0]+1,p[i].y)-sy;
ins(p[i].y+sx[0],p[i].x,1,0);
}ll ans=0;
F(i,1,K)ans+=EK(s[1].y+sx[0],s[top].x,sx[0]+sy[0]);
pi(ans);
return 0;
}
}
signed main(){return EMT::main();}
Everything that kills me makes me feel alive.