1. 程式人生 > >1135: [POI2009]Lyz

1135: [POI2009]Lyz

1135: [POI2009]Lyz

https://lydsy.com/JudgeOnline/problem.php?id=1135

分析:

  hall定理+線段樹連續區間的最大的和。

  首先轉化為二分圖的模型,然後根據hall定理

Hall定理:

此定理使用於組合問題中,二部圖G中的兩部分頂點組成的集合分別為X, Y, X={X1, X2, X3,X4,.........,Xm}, Y={y1, y2, y3, y4 ,.........,yn},G中有一組無公共點的邊,一端恰好為組成X的點的充分必要條件是:

X中的任意k個點至少與Y中的k個點相鄰。(1≤k≤m) 

  那麼如果直接列舉子集的話肯定不行,如果滿足了最劣的情況,那麼也就全滿足了,所以考慮如何求出最劣的情況。

  假設當前有連續的k個人[l,r],他們對應的鞋子區間是[l,r+d],那麼如果此時有l-1處有a[l-1]:如果a[l-1]>k,那麼將l-1和[l,r]這些人數的區間合成[l-1,r]的時候,增加的人數大於鞋子的個數,一定比分開算劣,所以就合起來。否則a[l-1]<=k,合起來比現在優,那麼就不合起來。

  所以最劣的情況就是對a[i]-k,求最大的子段和。

程式碼:    

 1 #include<cstdio>
 2 #include<algorithm>
 3
#include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0
,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int N = 200005; 20 21 struct Node{ 22 LL ls, rs, sum, mx; 23 }T[N << 2]; 24 LL a[N]; 25 26 void pushup(int rt) { 27 T[rt].ls = max(T[rt << 1].ls, T[rt << 1].sum + T[rt << 1 | 1].ls); 28 T[rt].rs = max(T[rt << 1 | 1].rs, T[rt << 1 | 1].sum + T[rt << 1].rs); 29 T[rt].sum = T[rt << 1].sum + T[rt << 1 | 1].sum; 30 T[rt].mx = max(T[rt << 1].rs + T[rt << 1 | 1].ls, max(T[rt << 1].mx, T[rt << 1 | 1].mx)); 31 } 32 void update(int l,int r,int rt,int p,LL x) { // LL x !!! 33 if (l == r) { 34 T[rt].ls = T[rt].rs = T[rt].sum = T[rt].mx = x; return ; 35 } 36 int mid = (l + r) >> 1; 37 if (p <= mid) update(l, mid, rt << 1, p, x); 38 else update(mid + 1, r, rt << 1 | 1, p, x); 39 pushup(rt); 40 } 41 int main() { 42 int n = read(), m = read(); LL k = read(), d = read(), mx = d * k; 43 n -= d; 44 for (int i = 1; i <= n; ++i) update(1, n, 1, i, -k); 45 while (m --) { 46 int p = read(), x = read(); 47 a[p] = a[p] + x; 48 update(1, n, 1, p, a[p] - k); 49 puts(T[1].mx <= mx ? "TAK" : "NIE"); 50 } 51 return 0; 52 }