Submission #1275550

#TimeUsernameProblemLanguageResultExecution timeMemory
1275550afonsopereiraAliens (IOI16_aliens)C++20
4 / 100
1 ms348 KiB
#include "aliens.h"
#include <vector>
#include <algorithm>
#include <deque>
using namespace std;

typedef long long ll;

class LinearFunction {
private:
    ll slope, intercept;
    
public:
    LinearFunction(ll m, ll c) : slope(m), intercept(c) {}
    
    ll evaluate(ll x) const {
        return slope * x + intercept;
    }
    
    ll getSlope() const { return slope; }
    ll getIntercept() const { return intercept; }
};

class ConvexHullTrick {
private:
    deque<LinearFunction> hull;

    bool isRedundant(const LinearFunction& left, const LinearFunction& mid, const LinearFunction& right) {
        __int128 lhs = (__int128)(left.getSlope() - right.getSlope()) * 
                       (__int128)(mid.getIntercept() - left.getIntercept());
        __int128 rhs = (__int128)(left.getSlope() - mid.getSlope()) * 
                       (__int128)(right.getIntercept() - left.getIntercept());
        return lhs <= rhs;
    }
    
public:
    void insert(LinearFunction func) {
        if (!hull.empty() && hull.front().getSlope() == func.getSlope()) {
            if (hull.front().getIntercept() <= func.getIntercept()) {
                return;
            }
            hull.pop_front();
        }

        while (hull.size() >= 2) {
            if (isRedundant(func, hull[0], hull[1])) {
                hull.pop_front();
            } else {
                break;
            }
        }
        
        hull.push_front(func);
    }
    
    ll queryMin(ll x) {
        while (hull.size() >= 2) {
            int lastIdx = hull.size() - 1;
            if (hull[lastIdx].evaluate(x) >= hull[lastIdx - 1].evaluate(x)) {
                hull.pop_back();
            } else {
                break;
            }
        }
        
        return hull.back().evaluate(x);
    }
};

struct Segment {
    int start, end;
    
    Segment(int s, int e) : start(s), end(e) {}
    
    bool operator<(const Segment& other) const {
        if (start != other.start) return start < other.start;
        return end > other.end;
    }
    
    ll coverage() const {
        return (ll)(end - start + 1) * (end - start + 1);
    }
};

vector<Segment> preprocessSegments(int n, vector<int>& r, vector<int>& c) {
    vector<Segment> segments;
    segments.reserve(n);
    
    for (int i = 0; i < n; i++) {
        int startPos = min(r[i], c[i]);
        int endPos = max(r[i], c[i]);
        segments.emplace_back(startPos, endPos);
    }
    
    sort(segments.begin(), segments.end());

    vector<Segment> filtered;
    int maxEnd = -1;
    
    for (const auto& seg : segments) {
        if (seg.end > maxEnd) {
            filtered.push_back(seg);
            maxEnd = seg.end;
        }
    }
    
    return filtered;
}

ll calculateOverlap(const Segment& prev, const Segment& curr) {
    if (curr.start > prev.end) return 0;
    ll overlap = prev.end - curr.start + 1;
    return overlap * overlap;
}

pair<ll, int> solveWithPenalty(const vector<Segment>& segments, ll penalty) {
    int n = segments.size();
    vector<ll> dp(n + 1, 1e18);
    vector<int> count(n + 1, 0);
    
    dp[0] = 0;
    ConvexHullTrick cht;
    
    for (int i = 0; i <= n; i++) {
        if (i > 0) {
            ll x = segments[i - 1].end;
            ll minCost = cht.queryMin(x);
            dp[i] = minCost + x * x + penalty;
        }
        
        if (i < n) {
            ll slope = -2 * segments[i].start + 2;
            ll overlap = (i > 0) ? calculateOverlap(segments[i - 1], segments[i]) : 0;
            ll base = segments[i].start - 1;
            ll intercept = dp[i] + base * base - overlap;
            
            cht.insert(LinearFunction(slope, intercept));
        }
    }
    
    // calculate number of segments used
    count[n] = 0;
    vector<ll> tempDp = dp;
    for (int i = n - 1; i >= 0; i--) {
        ll x = segments[i].end;
        ll costWithSegment = segments[i].coverage();
        if (i > 0) {
            costWithSegment -= calculateOverlap(segments[i - 1], segments[i]);
        }
        
        for (int j = i + 1; j <= n; j++) {
            if (dp[j] - dp[i] - penalty <= costWithSegment + 1e-9) {
                count[i] = count[j] + 1;
                break;
            }
        }
    }
    
    return {dp[n], count[0]};
}

long long take_photos(int n, int m, int k, vector<int> r, vector<int> c) {
    auto segments = preprocessSegments(n, r, c);
    n = segments.size();
    
    if (n <= k) {
        // can use one segment per point
        ll total = 0;
        for (int i = 0; i < n; i++) {
            total += segments[i].coverage();
            if (i > 0) {
                total -= calculateOverlap(segments[i - 1], segments[i]);
            }
        }
        return total;
    }

    ll left = 0, right = (ll)m * m;
    
    while (right - left > 2) {
        ll mid1 = left + (right - left) / 3;
        ll mid2 = right - (right - left) / 3;
        
        ll cost1 = solveWithPenalty(segments, mid1).first;
        ll cost2 = solveWithPenalty(segments, mid2).first;
        
        if (cost1 > cost2) {
            left = mid1;
        } else {
            right = mid2;
        }
    }
    
    ll result = 1e18;
    for (ll penalty = left; penalty <= right; penalty++) {
        auto [cost, numSegments] = solveWithPenalty(segments, penalty);
        if (numSegments <= k) {
            result = min(result, cost + (k - numSegments) * penalty);
        }
    }
    
    return result;
}

Compilation message (stderr)

aliens.h:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~
aliens_c.h:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~
#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...