1. 程式人生 > 實用技巧 >CF1452E Two Editorials【貪心】【差分】

CF1452E Two Editorials【貪心】【差分】

E. Two Editorials

按中點將線段排序,列舉選擇前幾個人去聽第一個老師的課,剩下的自然去到第二個老師。

列舉兩個老師選擇的區間,每次統計當前選擇的兩部分人與此區間的重合區間和,維護差分字首和。

差分字首和還要統計區間和,由於眾所周知本人很懶,不想用一個數組倒騰,於是開了兩個樹狀陣列。時間複雜度$O(n^2logn)$,用一個數組亂搞也只是偽$n^2$,妹有意思。

#include<bits/stdc++.h>
using namespace std;

int n, m, k;

struct Node {
    int l, r;
} stu[2005];

bool
cmp(Node a, Node b) { return (a.l + a.r) < (b.l + b.r); } int f[2005], las[2005], pre[2005], ini[2005]; int tr1[2005]; int lowbit(int x) { return x & (-x); } void add1(int pos, int d) { for(int i = pos; i <= n; i += lowbit(i)) tr1[i] += d; } int query1(int pos) { int ans = 0
; for(int i = pos; i; i -= lowbit(i)) ans += tr1[i]; return ans; } int tr2[2005]; void add2(int pos, int d) { for(int i = pos; i <= n; i += lowbit(i)) tr2[i] += d; } int query2(int pos) { int ans = 0; for(int i = pos; i; i -= lowbit(i)) ans += tr2[i];
return ans; } int main() { scanf("%d%d%d", &n, &m, &k); for(int i = 1; i <= m; i ++) { int a, b; scanf("%d%d", &a, &b); stu[i].l = a, stu[i].r = b; f[a] ++, f[b + 1] --; } sort(stu + 1, stu + m + 1, cmp); int ans = 0; for(int i = 1; i <= m; i ++) { ini[stu[i].l] ++, ini[stu[i].r + 1] --; int maxn = 0; memset(pre, 0, sizeof(pre)); memset(tr1, 0, sizeof(tr1)); for(int j = 1; j <= n; j ++) { pre[j] = pre[j - 1] + ini[j]; add1(j, pre[j]); if(j >= k) maxn = max(maxn, query1(j) - query1(j - k)); } f[stu[i].l] --, f[stu[i].r + 1] ++; int maxm = 0; memset(las, 0, sizeof(las)); memset(tr2, 0, sizeof(tr2)); for(int j = 1; j <= n; j ++) { las[j] = las[j - 1] + f[j]; add2(j, las[j]); if(j >= k) maxm = max(maxm, query2(j) - query2(j - k)); } ans = max(ans, maxm + maxn); } printf("%d", ans); return 0; }

這道題是夜宵前大佬們累了俺想出來的耶!