zoukankan      html  css  js  c++  java
  • 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
    */
  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/9147206.html
Copyright © 2011-2022 走看看