Submission #209561

#TimeUsernameProblemLanguageResultExecution timeMemory
209561oolimryAliens (IOI16_aliens)C++14
100 / 100
236 ms8036 KiB
#include "aliens.h"
#include <bits/stdc++.h>
using namespace std;

typedef pair<long long, long long> ii;
vector<ii> allRanges; ///all the ranges
vector<ii> arr; ///non-overalping ranges we need to consider

inline long long square(long long x){ return x * x; }

bool comp(ii a, ii b){
	if(a.first == b.first) return a.second > b.second;
	return a.first < b.first;
}

struct Line{ long long m, c, taken; };

inline long double intersect(Line a, Line b){
	return (long double) (b.c - a.c) / (long double) (a.m - b.m);
}

struct ConvexHull{
	Line hull[100005];
	int l = 0, r = -1;
	
	void reset(){
		l = 0, r = -1;
	}
	
	///take as many if tie by cost
	bool redundantBack(){
		if(r - l < 2) return false;
		if(abs(intersect(hull[r],hull[r-1]) - intersect(hull[r-2],hull[r])) <= 0.00000001) return hull[r].taken > hull[r-1].taken; 
		return intersect(hull[r-1],hull[r-2]) > intersect(hull[r],hull[r-2]);
	}
	
	///return the best value, and also how many ranges taken
	ii getBest(long long k){		
		while(r - l > 0 && intersect(hull[l],hull[l+1]) < (long double) k) l++;
		long long ans = (hull[l].m * k + hull[l].c);
		return ii(ans, hull[l].taken);
	}
	
	void addLine(long long m, long long c, long long taken){		
		if(r - l < 0 || hull[r].m > m) hull[++r] = {m,c,taken};
		else if(hull[r].c > c) hull[r] = {m,c,taken};
		else if(hull[r].c == c && hull[r].taken < taken) hull[r] = {m,c,taken}; ///tiebreak by no. taken
		
		while(redundantBack()){
			hull[r-1] = hull[r];
			r--;
		}
	}
	
	
} ch;


///This is the dp part. There is no restriction on the number of ranges.
///However, the dp value increases by cost for every range taken.
///This returns the optimum value and the max no. of ranges taken for that value of cost
inline ii monge(long long cost){
	ch.reset();
	ch.addLine(-2LL * arr[0].first, square(arr[0].first), 1); ///option for taking from the start
	
	ii dp; ///ii(bestAns, taken)
	for(int i = 0;i < (int) arr.size();i++){
		ii x = arr[i];
		dp = ch.getBest(x.second);
		dp.first += square(x.second);
		dp.first += cost; ///add a cost for taking a range
		
		if(i != (int) arr.size() - 1){
			long long gradient = -2 * arr[i+1].first;
			long long yIntercept = dp.first - square(max(0LL, arr[i].second - arr[i+1].first)) + square(arr[i+1].first);
			
			ch.addLine(gradient, yIntercept, dp.second + 1);
		}
	}
	
	return dp;
}

long long take_photos(int n, int m, int K, vector<int> L, vector<int> R) {

	for(int i = 0;i < n;i++){
		if(L[i] > R[i]) swap(L[i], R[i]);
		allRanges.push_back(ii(L[i],R[i]));
	}
	
	///sort the ranges
	sort(allRanges.begin(),allRanges.end(),comp);
	
	///remove all ranges which are fully contained in another
	int maxR = -1;
	for(ii r : allRanges){
		if(r.second > maxR){
			maxR = r.second;
			arr.push_back(ii(r.first,r.second+1));
		} 
	}
	
	if(arr.size() == 1){
		return square(arr[0].second - arr[0].first);
	}
		
	long long low = -1;
	long long high = square(m);
	
	///Let f(k) be the answer to the problem where k is the no. of ranges we take
	///f is concave upwards [f(i) - f(i+1) <= f(i-1) - f(i)], diminishing returns
	///Hence, if we let g(k) = f(k) + k * cost, then g(k) has a local minimum where gradient of f(k) = C
	///As C increases, the local minimum point decreases (greater cost -> take fewer ranges)
	///We can binary search the value of C such that the local minimum point occurs at K given in the qn
	while(true){
		if(low == high - 1) break;
		long long s = (low + high) / 2LL;
		
		if(monge(s).second <= K) high = s;
		else low = s;
	}
	
	///We need to do linear interpolation since the function is not strictly concave up
	ii ansHigh = monge(high);
	long long ans = ansHigh.first - K * high;
	
    return ans;
}
#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...