1. 程式人生 > >[uoj386][UNR #3]鴿子固定器【貪心】

[uoj386][UNR #3]鴿子固定器【貪心】

【題目連結】
  http://uoj.ac/problem/386
【題解】
  考慮先把序列按S排序後,將V從小到大從中刪去,刪去時用包含它的區間更新答案。
  為什麼答案一定是一段區間:由於數列中剩下的數V沒有比當前數更小的。用反證法,如果不是一段區間,那麼把當前點替換為區間隔開的點答案不會變劣。
  時間複雜度O(NM2)
【程式碼】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [UNR3Day1T1]
    Points :
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h> # 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 <ll, vector<ll>, greater<ll> > 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; }