제출 #36588

#제출 시각아이디문제언어결과실행 시간메모리
36588cheater2kAliens (IOI16_aliens)C++14
100 / 100
229 ms7588 KiB
#include "aliens.h"
#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second

struct ConvexHullTrick {
	// slopes are different from each other
	struct Line {
		long long a; long long b; int id; // b <= 1e12, a >= -2e6
		// id is the ID of the corresponding segment, which is useful for tracing
		Line(long long a=0, long long b=0, int id=0): a(a), b(b), id(id) {}
	};
	deque<Line> L;

	ConvexHullTrick() { L.clear(); }

	bool bad(Line l1, Line l2, Line l3) {
		return 1LL * (l1.b - l3.b) * (l2.a - l1.a) < 1LL * (l1.b - l2.b) * (l3.a - l1.a); // ~ [-2e18, 2e18]
	}
	void add(long long a, long long b, int id) {
		Line d = Line(a, b, id);
		while(L.size() >= 2 && bad(L[L.size()-2], L[L.size()-1], d)) L.pop_back();
		L.push_back(d);
	}
	long long func(Line &d, long long &x) {
		return 1LL * d.a * x + d.b;
	}
	pair<long long,int> get(long long x) {
		while(L.size() >= 2 && func(L[0], x) > func(L[1], x)) L.pop_front(); // L[0] is not good anymore
		return make_pair(func(L[0], x), L[0].id); // get the minimum ID
	}
} cht;

namespace Solver {
	const int N = 100005;
	pair<int, int> inp[N]; // input segments
	int l[N], r[N]; // leftmost and rightmost points of the segments
	int n, m, k;
	long long dp[N];
	int trace[N];

	void process() { // build new segments
		// no segment is contained by another segment
		sort(inp, inp + n, [&](pair<int,int> x, pair<int,int> y) {
			return x.fi < y.fi || (x.fi == y.fi && x.se > y.se);
		});
		int rmax = -1;
		int cnt = 0;
		for (int i = 0; i < n; ++i) {
			if (rmax < inp[i].se) {
				rmax = inp[i].se;
				++cnt;
				l[cnt] = inp[i].fi;
				r[cnt] = inp[i].se;
			}
		}
		n = cnt; // 1-based index now
	}

	int check(long long cost) {
		// reset
		cht = ConvexHullTrick();
		memset(dp, 0, sizeof dp);
		memset(trace, 0, sizeof trace);

		// dp[i] = (dp[j-1] - (max(0, r[j-1] - l[j]) ^ 2) + l[j] ^ 2) + (-2 * l[j]) * r[i] + r[i] ^ 2 (j <= i)

		// solve
		cht.add(-2 * l[1], 1LL * l[1] * l[1], 0);
		for (int i = 1; i <= n; ++i) {
			pair<long long, int> g = cht.get(r[i]);
			dp[i] = g.fi + 1LL * r[i] * r[i] + cost;
			trace[i] = g.se;
			long long cur = dp[i] - (1LL * max(0, r[i] - l[i+1]) * max(0, r[i] - l[i+1])) + 1LL * l[i+1] * l[i+1]; // b
			cht.add(-2 * l[i+1], cur, i);
		}

		// trace
		int pos = n, cnt = 0;
		while(pos) ++cnt, pos = trace[pos];
		return cnt;
	}

	long long solve() {
		process();
		// for (int i = 1; i <= n; ++i) {
		// 	printf("l[%d] = %d, r[%d] = %d\n", i, l[i], i, r[i]);
		// }

		long long l = 0, r = 1e13; // cost is positive
		while(l < r) {
			long long mid = ((l + r) >> 1);
			if (check(mid) <= k) r = mid; else l = mid + 1;
		}
		check(l);
		return dp[n] - l * k;
	}
};

long long take_photos(int n, int m, int k, vector<int> r, vector<int> c) {
	// init
	Solver::n = n;
	Solver::m = m; // square: [0...m-1][0...m-1]
	Solver::k = k;
	for (int i = 0; i < n; ++i) {
		if (r[i] > c[i]) swap(r[i], c[i]); // [r,c] is the corresponding segment in the diagonal
		Solver::inp[i].fi = r[i];
		Solver::inp[i].se = ++c[i];
	}

	// solve
	return Solver::solve();
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...