LOJios
暴力就直接連$O(n^2)$條邊。 而後分治/主席樹優化連邊就好了。 抄zsy代碼,zsy代碼是真的短優化
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define MAX 50000 const int inf=1e9; inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Line{int v,next,w,fy;}e[1000000]; int h[MAX],cnt=2; inline void Add(int u,int v,int w,int fy) { e[cnt]=(Line){v,h[u],w,fy};h[u]=cnt++; e[cnt]=(Line){u,h[v],0,-fy};h[v]=cnt++; } int S=0,T=0,tot; ll dis[MAX],vis[MAX],TIM; bool Update() { ll mn=1e18; for(int u=0;u<=tot;++u) if(vis[u]==TIM) for(int i=h[u];i;i=e[i].next) if(e[i].w&&vis[e[i].v]!=TIM) mn=min(mn,dis[e[i].v]+e[i].fy-dis[u]); if(mn>=inf)return false; for(int u=0;u<=tot;++u)if(vis[u]==TIM)dis[u]+=mn; return true; } ll Flow,Cost; int dfs(int u,int flow) { if(u==T||!flow){Flow+=flow;Cost+=dis[S]*flow;return flow;} int ret=0;vis[u]=TIM; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(vis[v]!=TIM&&e[i].w&&dis[v]==dis[u]-e[i].fy) { int d=dfs(v,min(flow,e[i].w)); flow-=d;ret+=d;e[i].w-=d;e[i^1].w+=d; if(!flow)break; } } return ret; } void ZKW() { do do ++TIM; while(dfs(S,inf)); while(Update()); } int n,W,a[MAX]; int p[MAX]; void Link(int l,int r) { if(l==r)return;int mid=(l+r)>>1; Link(l,mid);Link(mid+1,r); int t=0;for(int i=l;i<=r;++i)p[++t]=a[i]; sort(&p[1],&p[t+1]);t=unique(&p[1],&p[t+1])-p-1; for(int i=1;i<t;++i) { Add(tot+i,tot+i+1,inf,p[i+1]-p[i]); Add(tot+i+1,tot+i,inf,p[i+1]-p[i]); } for(int i=l;i<=r;++i) { int q=lower_bound(&p[1],&p[t+1],a[i])-p; if(i<=mid)Add(tot+q,i+n,1,0); else Add(i,tot+q,1,0); } tot+=t; } int main() { n=read();W=read(); for(int i=1;i<=n;++i)a[i]=read(); S=n+n+1;T=n+n+2;tot=n+n+2; for(int i=1;i<=n;++i)Add(S,i,1,0),Add(i,T,1,W),Add(i+n,T,1,0); Link(1,n);ZKW(); printf("%lld\n",Cost); return 0; }