CF 338E, 线段树
这道题真是太伤节奏了,做完之后好几天没动弹了。
题目大意:给你两个数组a、b,a长b短,对于以a每个位置开头与b等长的连续子序列,我们询问是否有这样一个匹配方式让子序列每个数和b中每个数一一对应相加且和大于给定的常数h。
解:没有想明白,去看官解没弄懂出题人是怎么分块瞎搞的。搜了一下题解,发现有一个更巧妙的解法,首先我们对b排序不会影响到结果,然后对于某个数,他在排序后的b里的合法匹配方案一定是连续的一段,这样就转化成了线段问题。对于Bn(从小到大排序的B数组),我们可知必须子序列里有n个数和他匹配,对于Bn-1,必须至少有n-1个数(因为可以允许有一个数匹配不了,但是匹配到Bn 上),于是等价于给定的n个线段覆盖让每个位置上的线段数>1,>2,>3 ... >n,如果开头把每个位置数都设成-1,-2,-3...-n,那么就是问n线段覆盖上去之后是否存在最小值小于零的格子(有则说明没有合法匹配)。至此我们便把原问题转化成线段树可做的问题。
我大概yy了一下,貌似这个做法不能推广到区间资源分配上,因为这个问题的特殊性在于他是一个萝卜一个坑,而且合法的线段一定是延伸到n的。
1 #include <cstdio> 2 #include <string> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <cstring> 7 #include <complex> 8 #include <set> 9 #include <vector> 10 #include <map> 11 #include <queue> 12 #include <deque> 13 #include <ctime> 14 15 using namespace std; 16 17 const double EPS = 1e-8; 18 19 #define ABS(x) ((x)<0?(-(x)):(x)) 20 #define SQR(x) ((x)*(x)) 21 #define MIN(a,b) ((a)<(b)?(a):(b)) 22 #define MAX(a,b) ((a)>(b)?(a):(b)) 23 24 #define LSON(x) ((x)<<1) 25 #define RSON(x) (((x)<<1)+1) 26 #define LOWBIT(x) ((x)&(-(x))) 27 #define MAXS 1111 28 #define MAXN 222222 29 #define VOIDPOINT 0 30 #define LL long long 31 #define OO 214748364 32 33 struct SegTree{ 34 int l[MAXN*4], r[MAXN*4], m[MAXN*4], minn[MAXN*4], lazy[MAXN*4]; 35 int gx, gy, gz; 36 void set(int a = 0, int b = 0, int c = 0) { 37 gx = a; gy = b; gz = c; 38 } 39 inline void updata(int kok) { 40 minn[kok] = min(minn[LSON(kok)], minn[RSON(kok)]); 41 } 42 inline void pushDown(int kok) { 43 if (l[kok] != r[kok]) { 44 lazy[LSON(kok)] += lazy[kok]; 45 minn[LSON(kok)] += lazy[kok]; 46 lazy[RSON(kok)] += lazy[kok]; 47 minn[RSON(kok)] += lazy[kok]; 48 } 49 lazy[kok] = 0; 50 } 51 void build(int kok, int ll, int rr) { 52 l[kok] = ll; r[kok] = rr; lazy[kok] = 0; 53 if (ll == rr) { 54 minn[kok] = -ll; 55 return ; 56 } 57 int mid = m[kok] = (ll + rr) >> 1; 58 build(LSON(kok), ll, mid); build(RSON(kok), mid+1, rr); 59 updata(kok); 60 } 61 void insert(int kok) { 62 if (gx > gy) return ; 63 if (gx <= l[kok] && r[kok] <= gy) { 64 lazy[kok] += gz; minn[kok] += gz; 65 pushDown(kok); 66 return ; 67 } 68 if (lazy[kok]) 69 pushDown(kok); 70 int mid = m[kok]; 71 if (gx <= mid) insert(LSON(kok)); 72 if (gy > mid) insert(RSON(kok)); 73 updata(kok); 74 } 75 } Tree; 76 77 int a[MAXN], b[MAXN], n, len, h; 78 79 int main() { 80 // freopen("test.txt", "r", stdin); 81 82 scanf("%d%d%d", &n, &len, &h); 83 for (int i = 1; i <= len; ++i) scanf("%d", &b[i]); 84 sort(b+1, b+1+len); 85 Tree.build(1, 1, len); 86 int ans = 0; 87 for (int i = 1; i <= n; ++i) { 88 scanf("%d", &a[i]); a[i] = h - a[i]; 89 a[i] = lower_bound(b+1, b+1+len, a[i]) - b; 90 if (i < len) { 91 Tree.set(a[i], len, 1); 92 Tree.insert(1); 93 } 94 } 95 for (int i = len; i <= n; ++i) { 96 Tree.set(a[i], len, 1); 97 Tree.insert(1); 98 ans += Tree.minn[1] >= 0 ? 1: 0; 99 Tree.set(a[i-len+1], len, -1); 100 Tree.insert(1); 101 } 102 printf("%d\n", ans); 103 return 0; 104 }
附上官解页面,以后有空要搞搞明白别人是怎么分块乱搞的:http://codeforces.com/blog/entry/8629