NOIP模拟68
T1:
考场上考虑的时路径,即考虑路径完全相同这一条件然而显然路径数非常多,
这种思路无法避开路径的具体信息,因此并不正确,然而n = 2的点可以通过该方式哈希判断,因此未找到正确思路
正解比较显然,当s[i + 1][j] == s[i][j + 1]时显然可以运送两人,因此当存在可以连接上的两处该位置时即可运送四人
也就是问题转化为判断是否存在能够连接上的两处该种位置,二维前缀和即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It's Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I N = 1005; 20 I T,n,m,Pre[N][N]; 21 C s[N][N]; 22 inline I read () { 23 I x(0),y(1); C z(getchar()); 24 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 25 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 26 return x * y; 27 } 28 inline V Max (I &a,I b) { a = a > b ? a : b; } 29 inline V Min (I &a,I b) { a = a < b ? a : b; } 30 inline I max (I a,I b) { return a > b ? a : b; } 31 inline I min (I a,I b) { return a < b ? a : b; } 32 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 33 inline I abs (I a) { return a >= 0 ? a : -a; } 34 inline P operator + (const P &a,const P &b) { 35 return MP (a.a + b.a,a.b + b.b); 36 } 37 inline P operator - (const P &a,const P &b) { 38 return MP (a.a - b.a,a.b - b.b); 39 } 40 inline B Check (I i,I j) { return s[i + 1][j] == s[i][j + 1]; } 41 signed main () { 42 FP (water.in), FC (water.out); 43 T = read (); 44 while (T -- ) { 45 n = read (), m = read (); 46 for (I i(1);i <= n; ++ i) 47 scanf ("%s",s[i] + 1); 48 for (I i(2);i <= n; ++ i) 49 for (I j(2);j <= m; ++ j) 50 Pre[i][j] = Pre[i][j - 1] + Pre[i - 1][j] - Pre[i - 1][j - 1] + Check (i - 1,j - 1); 51 B flag (0); 52 for (I i(1);i < n; ++ i) 53 for (I j(1);j < m; ++ j) if (Check (i,j)) 54 if (Pre[i][j] || Check (i,j - 1) || Check (i - 1,j)) 55 flag = 1; 56 flag ? puts ("1") : puts ("0"); 57 } 58 }
T3:
比较显然的策略为a从大到小排序进行配对,考虑形式话,得到问题实质上时求是否对于所有k(1 <= k <= n)
满足:sigma a[k] <= sigma min(b[i],k),考虑如何优化,从min着手,考虑拆min,max类型一种方式为分类讨论
通过权值数据结构进行维护,另一种方式即为类似筛法,考虑b[i]与k中每一个1的贡献,可以得到,若设c[i]为满足b[x] >= i的个数
那么原式等价于sigma a <= sigma c,进一步化简得到sigma (c - a) >= 0,比较套路的做法,利用数据结构维护最小值,这样只需要
判断最小值是否满足要求即可,这也启示我们对于这类判断题,通常可以将整体判断转化为极值判断降低时间复杂度
于是首先根据c - a建树,每次操作区间修改即可,注意线段树内部并不能实现随机访问,因此一般先处理线段树初始值,再利用其做维护操作
另外,c数组的求解方法也值得思考,同样类似筛法,将b数组进行排序,当前b数组中数量即为c数组值,当c数组下表变化时,动态维护b即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It's Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I N = 2.5e5 + 3; 20 I n,m,q,it,pos,a[N],b[N],c[N],Pre[N],ar[N],br[N]; 21 inline I read () { 22 I x(0),y(1); C z(getchar()); 23 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 24 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 25 return x * y; 26 } 27 inline V Max (I &a,I b) { a = a > b ? a : b; } 28 inline V Min (I &a,I b) { a = a < b ? a : b; } 29 inline I max (I a,I b) { return a > b ? a : b; } 30 inline I min (I a,I b) { return a < b ? a : b; } 31 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 32 inline I abs (I a) { return a >= 0 ? a : -a; } 33 inline P operator + (const P &a,const P &b) { 34 return MP (a.a + b.a,a.b + b.b); 35 } 36 inline P operator - (const P &a,const P &b) { 37 return MP (a.a - b.a,a.b - b.b); 38 } 39 struct SGT { 40 #define lid id << 1 41 #define rid id << 1 | 1 42 #define mid (l + r >> 1) 43 #define update(id) (MI[id] = min (MI[lid],MI[rid])) 44 I MI[N << 2],lazy[N << 2]; 45 inline V pushdown (I id) { 46 MI[lid] += lazy[id], lazy[lid] += lazy[id]; 47 MI[rid] += lazy[id], lazy[rid] += lazy[id]; 48 lazy[id] = 0; 49 } 50 V found (I id,I l,I r) { 51 if (l == r) return (V)(MI[id] = Pre[l]); 52 found (lid,l,mid), found (rid,mid + 1,r); 53 update (id); 54 } 55 V secmod (I id,I l,I r,I ql,I qr,B typ) { 56 if (ql > qr || ql <= 0) return ; 57 if (ql <= l && r <= qr) 58 return (V)(typ ? (MI[id] ++ ,lazy[id] ++) : (MI[id] -- ,lazy[id] --)); 59 if (lazy[id] && l != r) pushdown (id); 60 if (ql <= mid) secmod (lid,l,mid,ql,qr,typ); 61 if (qr > mid) secmod (rid,mid + 1,r,ql,qr,typ); 62 update (id); 63 } 64 }SGT; 65 signed main () { 66 FP (problem.in), FC (problem.out); 67 n = read (), m = read (); 68 for (I i(1);i <= n; ++ i) 69 ar[i] = a[i] = read (); 70 for (I i(1);i <= m; ++ i) 71 br[i] = b[i] = read (); 72 sort (b + 1,b + m + 1); 73 for (I i(1),tmp(m); tmp ; c[i++] = tmp) 74 while (i > b[m - tmp + 1] && tmp) tmp -- ; 75 sort (a + 1,a + n + 1); 76 for (I i(1);i <= n; ++ i) 77 Pre[i] = Pre[i - 1] + c[i] - a[n - i + 1]; 78 SGT.found (1,1,n); 79 q = read (); 80 while (q -- ) { 81 switch (read ()) { 82 case 1 : pos = read (); 83 it = upper_bound (a + 1,a + n + 1,ar[pos]) - a - 1; 84 a[it] ++ , ar[pos] ++ ; SGT.secmod (1,1,n,n - it + 1,n,0); 85 break; 86 case 2 : pos = read (); 87 it = lower_bound (a + 1,a + n + 1,ar[pos]) - a; 88 a[it] -- , ar[pos] -- ; SGT.secmod (1,1,n,n - it + 1,n,1); 89 break; 90 case 3 : SGT.secmod (1,1,n,++ br[read ()],n,1); break; 91 case 4 : SGT.secmod (1,1,n,br[read ()] --,n,0); break; 92 } 93 SGT.MI[1] >= 0 ? puts ("1") : puts ("0"); 94 } 95 }