1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
| #include<bits/stdc++.h> #define int long long using namespace std; const int N = 3005; const int INF = 1e18+5; struct edge{ int nxt,to,cost,val; edge(){} edge(int _nxt,int _to,int _val,int _cost){ nxt = _nxt,to = _to,cost = _cost,val = _val; } }e[5000 * N]; int cnt=1,tot,s,t,pre[N],suf[N],b[N],tmp[N],in[5 * N],out[5 * N],a[5 * N],dis[5 * N],cur[5 * N],head[5 * N]; bool in_que[5 * N],vis[5 * N]; void add_edge(int from,int to,int val,int cost){ e[++cnt] = edge(head[from],to,val,cost); head[from] = cnt; e[++cnt] = edge(head[to],from,0,-cost); head[to] = cnt; } bool spfa(){ for(int i=1; i<=tot; i++) dis[i] = INF,in_que[i] = false,cur[i] = head[i]; dis[s] = 0; queue<int> q;q.push(s);in_que[s] = true; while(!q.empty()){ int now = q.front();q.pop(); in_que[now] = false; for(int i=head[now]; i; i=e[i].nxt){ int to = e[i].to; if(dis[to] > dis[now] + e[i].cost && e[i].val){ dis[to] = dis[now] + e[i].cost; if(!in_que[to]) q.push(to),in_que[to] = true; } } } return dis[t] != INF; } int dfs(int now,int limit){ if(now == t) return limit; int flow = 0;vis[now] = true; for(int i=cur[now]; i && flow < limit; i=e[i].nxt){ int to = e[i].to; cur[now] = i; if(e[i].val && dis[to] == dis[now] + e[i].cost && !vis[to]){ int h = dfs(to,min(e[i].val,limit-flow)); e[i].val -= h,e[i^1].val += h; flow += h; if(!h) dis[to] = INF; } } return flow; } int dinic(){ int ans = 0; while(spfa()){ memset(vis,false,sizeof(vis)); int flow = dfs(s,INF); ans += flow * dis[t]; } return ans; } int find(int l,int r,int val){ int ans = r + 1; while(l <= r){ int mid = (l + r) >> 1; if(a[b[mid]] > val){ ans = mid,r = mid - 1; } else l = mid + 1; } return ans; } void solve(int l,int r){ if(l == r) return; int mid = (l + r) >> 1; solve(l,mid);solve(mid+1,r); for(int i=l; i<=mid; i++){ pre[i] = ++tot; add_edge(pre[i],out[b[i]],1,-a[b[i]]); if(i != l) add_edge(pre[i],pre[i-1],INF,0); } for(int i=mid; i>=l; i--){ suf[i] = ++tot; add_edge(suf[i],out[b[i]],1,a[b[i]]); if(i != mid) add_edge(suf[i],suf[i+1],INF,0); } for(int i=mid+1; i<=r; i++){ int pos = find(l,mid,a[b[i]]); if(pos-1 >= l) add_edge(in[b[i]],pre[pos-1],1,a[b[i]]); if(pos <= mid) add_edge(in[b[i]],suf[pos],1,-a[b[i]]); } int sz = l-1; int posl = l,posr = mid+1; while(posl <= mid && posr <= r){ if(a[b[posl]] < a[b[posr]]) tmp[++sz] = b[posl++]; else tmp[++sz] = b[posr++]; } while(posl <= mid) tmp[++sz] = b[posl++]; while(posr <= r) tmp[++sz] = b[posr++]; for(int i=l; i<=r; i++) b[i] = tmp[i]; } signed main(){
int n,W;scanf("%lld%lld",&n,&W); s = ++tot; t = ++tot; int p = ++tot;add_edge(p,t,INF,0); for(int i=1; i<=n; i++) in[i] = ++tot,out[i] = ++tot; for(int i=1; i<=n; i++){ scanf("%lld",&a[i]); add_edge(s,in[i],1,0);add_edge(out[i],t,1,0); add_edge(in[i],p,1,W); } for(int i=1; i<=n; i++) b[i] = i; solve(1,n); printf("%lld\n",dinic()); return 0; }
|