300iq Contest 2 H Honorable Mention(凸優化、wqs二分+線段樹分治+整體思想)


http://codeforces.com/gym/102331/problem/H

題解:

首先,當\(k\)很小時,有一經典模擬費用流做法:
每次找到最大的子區間,加上它,並把它取反,可以用線段樹維護。

但這題\(k\)\(n\)同階,需要思考其它的做法。

還可以凸優化dp,二分斜率k后用單調隊列就可以\(O((r-l+1)*log~V)\)做一次。

考慮優化一些這個dp,顯然可以放到線段樹上分治。

那么對於每一個區間需要求出斜率為k時最優選的和和區間個數。

對線段樹上每個區間預處理選\(?\)段時的最大和,這個是凸的,所以在上面二分可以得到斜率為k的最優值。

注意每個區間要記錄左右邊界選了沒有(因為合並是如果兩個端點都選了可以少一段)

線段樹區間的預處理可以用閔科夫斯基和從子區間推來。

這樣復雜度是\(O(16*n~log~n+8*(Q*log~V*log~n*log~n))\)

可定TLE了。

注意對同一層二分的查詢,可以先排序,到線段樹每個區間就可以指針找最小值(指針移動距離不超過\(n log n\)),這樣復雜度變為:\(O(16*n~log~n+8*(Q*log~V*log~n)+n~log~n*log~V)\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 3.5e4 + 5;

const ll inf = 1225000000ll;

int n, Q;
ll a[N];

#define V vector<ll>
#define si size()

V t[N * 4][2][2];

#define i0 i + i
#define i1 i + i + 1

void gx(V &a, V b, V c) {
	int n = b.si - 1, m = c.si - 1;
	a.resize(n + m + 1);
	ll s = b[0] + c[0]; a[0] = s;
	int l = 0, r = 0;
	while(l < n && r < m) {
		if(b[l + 1] - b[l] > c[r + 1] - c[r]) {
			s += b[l + 1] - b[l];
			l ++;
		} else {
			s += c[r + 1] - c[r];
			r ++;
		}
		a[l + r] = s;
	}
	while(l < n) s += b[l + 1] - b[l], l ++, a[l + r] = s;
	while(r < m) s += c[r + 1] - c[r], r ++, a[l + r] = s;
}

void fz(V &a, V b, int op) {
	ff(i, 0, b.si)	{
		a[i] = max(a[i], b[i]);
		if(op && i) {
			a[i - 1] = max(a[i - 1], b[i]);
		}
	}
}

void bt(int i, int x, int y) {
	if(x == y) {
		fo(u, 0, 1) fo(v, 0, 1) {
			t[i][u][v].resize(2);
			t[i][u][v][0] = t[i][u][v][1] = -inf;
			if(u == 0 && v == 0) t[i][u][v][0] = 0;
			if(u == 1 && v == 1) t[i][u][v][1] = a[x];
		}
		return;
	}
	int m = x + y >> 1;
	bt(i0, x, m); bt(i1, m + 1, y);
	int len = y - x + 1;
	fo(u, 0, 1) fo(v, 0, 1) {
		t[i][u][v].resize(len + 1);
		fo(j, 0, len) t[i][u][v][j] = -inf * n;
	}
	fo(u, 0, 1) fo(v, 0, 1) fo(p, 0, 1) fo(q, 0, 1) {
		V b;
		gx(b, t[i0][u][v], t[i1][p][q]);
		fz(t[i][u][q], b, (v && p));
	}
}

void build() {
	fo(i, 1, n) scanf("%lld", &a[i]);
	bt(1, 1, n);
}

struct nod {
	int x, y, k;
} b[N];

int L[N], R[N], m[N], as[N];

int d[N];

int cmpd(int x, int y) {
	return m[x] > m[y];
}

int l[N * 4][2][2];

int pl, pr;

int mk;

struct P {
	ll x; int y;
	P(ll _x = 0, int _y = 0) {
		x = _x, y = _y;
	}
};

P operator + (P a, P b) { return P(a.x + b.x, a.y + b.y);}
bool operator < (P a, P b) { return a.x == b.x ? a.y < b.y : a.x < b.x;}

P f[2], h[2];

int find(V &g, int &l) {
	while(l < g.si - 1 && g[l + 1] - g[l] >= mk) l ++;
	return l;
}

void gg(P *f, V (*g)[2], int (*l)[2]) {
	fo(x, 0, 1) {
		h[x] = f[x];
		f[x] = P(-inf, -inf);
	}
	fo(u, 0, 1)	fo(v, 0, 1) {
		int w = find(g[u][v], l[u][v]);
		P e = P(g[u][v][w], w);
		fo(x, 0, 1) {
			P nf = h[x] + e;
			nf.x -= e.y * mk;
			f[v] = max(f[v], nf);
			if(x == 1 && u == 1) {
				nf.y --, nf.x += mk;
				f[v] = max(f[v], nf);
			}
		}
	}
}

void ft(int i, int x, int y) {
	if(y < pl || x > pr) return;
	if(x >= pl && y <= pr) {
//		pp("%d %d %d mk = %d\n", i, x, y, mk);
		gg(f, t[i], l[i]);
		return;
	}
	int m = x + y >> 1;
	ft(i0, x, m); ft(i1, m + 1, y);
}

ll ans[N];

void End() {
	int js = 0;
	fo(i, 1, n) js += abs(a[i]);
	fo(i, 1, Q) {
		scanf("%d %d %d", &b[i].x, &b[i].y, &b[i].k);
		L[i] = -35000, R[i] = js / b[i].k;
	}
	while(1) {
		fo(i, 1, Q) {
			m[i] = ((ll) L[i] + R[i]) / 2;
			d[i] = i;
		}
		sort(d + 1, d + Q + 1, cmpd);
		memset(l, 0, sizeof l);
		int ok = 0;
		fo(i, 1, Q) {
			int x = d[i];
			if(L[x] > R[x]) continue;
			ok = 1;
			mk = m[x];
			pl = b[x].x, pr = b[x].y;
			f[0] = P(0, 0); f[1] = P(-inf, inf);
			ft(1, 1, n);
			f[0] = max(f[0], f[1]);
			if(f[0].y >= b[x].k) {
				as[x] = m[x];
				L[x] = m[x] + 1;
			} else {
				R[x] = m[x] - 1;
			}
		}
		if(!ok) break;
	}
	memset(l, 0, sizeof l);
	fo(i, 1, Q) d[i] = i, m[i] = as[i];
	sort(d + 1, d + Q + 1, cmpd);
	fo(i, 1, Q) {
		int x = d[i];
		mk = as[x];
		pl = b[x].x, pr = b[x].y;
		f[0] = P(0, 0); f[1] = P(-inf, inf);
		ft(1, 1, n);
		f[0] = max(f[0], f[1]);
		ans[x] = f[0].x + b[x].k * mk;
	}
	fo(i, 1, Q) pp("%lld\n", ans[i]);
}

int main() {
	freopen("maximize.in", "r", stdin);
	freopen("maximize.out", "w", stdout);
	scanf("%d %d", &n, &Q);
	build();
	End();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM