【题解】CF1615H Reindeer Games
保序回归问题,给定偏序集和 \(\{a_i\}\),求 \(\{b\}\) 使得 \(\sum|a_i-b_i|^k\) 最小。
关键结论,假设最优解是 \(\{b\}\),如果每个 \(b\) 只能是 \(x,x+\epsilon\),那么对于这个子问题的最优解是 \(\{c|c_i = b_i \le x ? x : x+\epsilon\}\)。
反过来的结论同样成立,我们求得 \(\{c\}\),那么如果 \(c_i = x\) 则 \(b_i \le x\),否则 \(b_i > x\)。
所以我们可以整体二分,现在转化为如何求 \(\{c\}\),很明显每个位置只有两个取值,我们先钦定每个数为 \(x\),考虑将一些数变为 \(x+\epsilon\),那么这就是经典的最大闭合权子图,直接跑最大流即可。
#define N 1005
int n, m, a[N], u[N], ed[N], mat[N], v[N];
vector<int>c[N];
int h[N], tot, d[N], s, t, cur[N];
queue<int>q;
struct edge{int to, nxt, cap;}e[N << 3];
void add(int x,int y,int cap){
e[++tot].nxt = h[x], h[x] = tot, e[tot].to = y, e[tot].cap = cap;
e[++tot].nxt = h[y], h[y] = tot, e[tot].to = x, e[tot].cap = 0;
}
bool bfs(){
rp(i, t)d[i] = 0, cur[i] = h[i];
d[s] = 1; q.push(s);
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = h[x]; i; i = e[i].nxt)if(e[i].cap && !d[e[i].to])
d[e[i].to] = d[x] + 1, q.push(e[i].to);
}
return d[t] > 0;
}
int dfs(int x,int flow){
if(t == x)return flow;
int res = flow;
for(int &i = cur[x]; i; i = e[i].nxt)if(d[e[i].to] == d[x] + 1 && e[i].cap){
int now = dfs(e[i].to, min(res, e[i].cap));
if(!now)d[e[i].to] = 0;
else e[i].cap -= now, e[i ^ 1].cap += now, res -= now;
if(!res)return flow;
}
return flow - res;
}
void solve(int l,int r,int L,int R){
if(l > r)return;
//cout << "ss " << l << " " << r << " " << L << " " << R << endl;
if(L == R){rep(i, l, r)ed[u[i]] = L; return;}
int mid = (L + R) >> 1;
s = r - l + 2, t = s + 1;
tot = 1; rp(i, t)h[i] = 0;
rep(i, l, r){
//int val = mid >= a[u[i]] ? -1 : 1;
if(mid < a[u[i]])add(s, i - l + 1, 1);
else add(i - l + 1, t, 1);
mat[u[i]] = i - l + 1;
}
rep(i, l, r)go(y, c[u[i]])if(mat[y])add(i - l + 1, mat[y], inf);
rep(i, l, r)mat[u[i]] = 0;
while(bfs())dfs(s, inf);
int ls = l, rs = r;
rep(i, l, r){
if(d[i - l + 1] > 0)v[rs--] = u[i];
else v[ls++] = u[i];
}
rep(i, l, r)u[i] = v[i];
solve(l, ls - 1, L, mid), solve(ls, r, mid + 1, R);
}
int main() {
read(n, m); int r = 1;
rp(i, n)read(a[i]), u[i] = i, cmx(r, a[i]);
rp(i, m){
int x, y;
read(x, y);
c[x].pb(y);
}
solve(1, n, 1, r);
rp(i, n)printf("%d ", ed[i]); el;
return 0;
}