[uoj386][UNR #3]鸽子固定器【贪心】

【题目链接】
  http://uoj.ac/problem/386
【题解】
  考虑先把序列按 S S 排序后,将 V V 从小到大从中删去,删去时用包含它的区间更新答案。
  为什么答案一定是一段区间:由于数列中剩下的数 V V 没有比当前数更小的。用反证法,如果不是一段区间,那么把当前点替换为区间隔开的点答案不会变劣。
  时间复杂度 O(NM2) O ( N M 2 )
【代码】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [UNR3Day1T1]
    Points :
- - - - - - - - - - - - - - - */
# include 
# define    ll      long long
# define    N       200010
using namespace std;
const int inf = 0x3f3f3f3f, INF = 0x7fffffff;
const ll  infll = 0x3f3f3f3f3f3f3f3fll, INFll = 0x7fffffffffffffffll;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Node{ll s, v;}p[N];
bool cmp(Node x, Node y){return x.s < y.s;}
priority_queue vector, greater > hp;
int n, m, S, V;
ll ans;
void chkans(ll sum, ll det){
    ll num1, num2;
    if (V == 1) num1 = sum; else num1 = sum * sum;
    if (S == 1) num2 = det; else num2 = det * det;
    ans = max(ans, num1 - num2);
}
int main(){
    n = read(), m = read(), S = read(), V = read();
    for (int i = 1; i <= n; i++)
        p[i].s = read(), p[i].v = read();
    sort(p + 1, p + n + 1, cmp);
    ans = -INFll;
    for (int i = 1; i <= n; i++){
        while (hp.size() > 0) hp.pop();
        ll now = 0;
        for (int j = i; j <= n; j++){
            if (hp.size() == m){
            if (hp.top() < p[j].v){
                now = now - hp.top() + p[j].v;
                hp.pop();
                hp.push(p[j].v);
            }
            }
            else {
                now = now + p[j].v;
                hp.push(p[j].v);
            }
            chkans(now, p[j].s - p[i].s);
        }
    }
    printf("%lld\n", ans);
    return 0;
}

你可能感兴趣的:([uoj386][UNR #3]鸽子固定器【贪心】)