ioi2016aliens

/*
首先考虑点在直线的两边效果一样 于是转移到一边
之后发现当我们覆盖某些点时,有其他的一些点一定会被覆盖  我们找出所有必须覆盖的点
之后我们发现我们找到的这些点 将其按照x递增排序 那么y也是递增的 
然后我们 可以得到转移方程了 令dp[i][j]表示前i个都覆盖到了,用了j个正方形的最小花费

然后我们考虑转移时的枚举dp[i][j] = min(dp[i][k] + (x[i] - y[k + 1] + 1) ^ 2;
 
这个是显然NKN的, 斜率优化后NK, wqs二分后Nlogm 


*/


//#include "aliens.h"
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector> 
using namespace std;
#define M 100010
#define ll long long
#define inf 0x3f3f3f3f
struct Note{
    ll x, y;
    bool operator < (const Note &b) const{
        return this->x == b.x ? this->y > b.y : this->x < b.x;
    }
}note[M], p[M];
int tot,q[M],h,t, sm[M]; 
ll dp[M], ans;


double X(int x) {return p[x + 1].y;}
double Y(int x) {return dp[x] - 2 * p[x + 1].y + p[x + 1].y * p[x + 1].y;}
double slope(int x, int y) {return (Y(x) - Y(y)) / (X(x) - X(y));} 

int solve(ll x)
{
    h = 1, t = 1, q[1] = 0;
    for(int i = 1; i <= tot; i++)
    {
        while(h < t && 2.0 * p[i].x > slope(q[h], q[h + 1])) h++;
        dp[i] = dp[q[h]] + (p[i].x - p[q[h] + 1].y + 1) * (p[i].x - p[q[h] + 1].y + 1) + x;
        sm[i] = sm[q[h]] + 1;
        if(i == tot) break;
        if(p[i + 1].y <= p[i].x) dp[i] -= (p[i].x - p[i + 1].y + 1) * (p[i].x - p[i + 1].y + 1);
        while(h < t && slope(q[t], q[t - 1]) > slope(q[t], i)) t--;
        q[++t] = i; 
    }
    return sm[tot];
}

long long take_photos(int n, int m, int k, std::vector<int> r, std::vector<int> c) {
    for(int i = 0; i < n; i++) 
    {
        note[i].y = r[i], note[i].x = c[i];
        if(note[i].x < note[i].y) swap(note[i].x, note[i].y);
    }
    sort(note, note + n);
    for(int i = 1; i < n; i++)    
    {
        while(h <= t && note[i].y <= note[q[t]].y ) t--;
        q[++t] = i;
    }
    for(int i = h; i <= t; i++){tot++;p[tot].x = note[q[i]].x, p[tot].y = note[q[i]].y;}
    if((ans = solve(0)) <= k) {
        return dp[tot];
    }
    ll L = 0, R = 1ll * m * m + 10;
    while(L <= R)
    {
        ll mid = (L + R) >> 1;
        if(solve(mid) <= k) R = mid - 1, ans = dp[tot];
        else L = mid + 1;
    }
//    if(ans - 1ll * R * k - k == 568367396612){solve(107455936237); return sm[tot];}
    return ans - 1ll * R * k - k;
}
/*
5 7 2
0 4 4 4 4 
3 4 6 5 6

2 6 2
1 4
4 1

4 4 4
1 0 2 2
3 1 1 2

1 3
0 1
2 1
2 2
*/

猜你喜欢

转载自www.cnblogs.com/luoyibujue/p/9147206.html