Codeforces Round #524 (Div. 2) Solution
A. Petya and Origami
Water.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 ll n, k; 6 7 ll Get(ll x) 8 { 9 return (x * n) % k == 0 ? (x * n) / k : (x * n) / k + 1; 10 } 11 12 int main() 13 { 14 while (scanf("%lld%lld", &n, &k) != EOF)View Code15 { 16 ll res = Get(2) + Get(5) + Get(8); 17 printf("%lld\n", res); 18 } 19 return 0; 20 }
B. Margarite and the best present
Water.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 int q, l, r; 6View Codell get(ll x) 7 { 8 return x * ((x & 1) ? -1 : 1); 9 } 10 11 int main() 12 { 13 while (scanf("%d", &q) != EOF) 14 { 15 for (int qq = 1; qq <= q; ++qq) 16 { 17 scanf("%d%d", &l, &r); 18 if (l == r) printf("%lld\n", get(l)); 19 else20 { 21 ll res = 0; 22 if ((l & 1) == 0) res = get(l++); 23 if (r & 1) res += get(r--); 24 res += ((r - l + 1) >> 1); 25 printf("%lld\n", res); 26 } 27 } 28 } 29 return 0; 30 }
C. Masha and two friends
Upsolved.
題意:
有一個黑白相間的棋盤,第一次選擇一個矩形區域將區域內所有格子染白
第二次選擇一個矩形區域將所有格子染黑,求最後白方塊個數和黑方塊個數
思路:
考慮先求整個棋盤的黑白方塊個數,再刪除兩塊矩形的黑白方塊個數,矩形交部分要加一次
再求染色後,增加的黑塊和白塊個數
考慮怎麼求黑白相間的黑白方塊個數,發現如果矩形有一邊長為偶數,那麼兩種顏色數量相同
否則,左下角是什麼顏色,這個顏色的方塊就多一個
其實,只求一種顏色就好了,因為總數是不變的
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define pll pair <ll, ll> 6 int t; ll x[4], y[4], X[2], Y[2], n, m, white, black; 7 pll tmp; 8 9 pll get(ll n, ll m, int vis) 10 { 11 ++n, ++m; 12 pll res = pll(0, 0); 13 if ((n & 1) && (m & 1)) 14 { 15 res.first = res.second = ((n - 1) * m) >> 1; 16 res.first += (m >> 1) + 1ll * (vis ^ 1); 17 res.second += (m >> 1) + 1ll * vis; 18 } 19 else 20 res.first = res.second = (n * m) >> 1; 21 return res; 22 } 23 24 ll get2(ll n, ll m) { ++n, ++m; return n * m; } 25 26 int main() 27 { 28 scanf("%d", &t); 29 while (t--) 30 { 31 scanf("%lld%lld", &n, &m); 32 for (int i = 0; i < 4; ++i) scanf("%lld%lld", x + i, y + i); 33 tmp = get(n - 1, m - 1, 0); 34 white = tmp.first, black = tmp.second; 35 tmp = get(y[1] - y[0], x[1] - x[0], (x[0] & 1) ^ (y[0] & 1)); 36 white -= tmp.first; black -= tmp.second; 37 tmp = get(y[3] - y[2], x[3] - x[2], (x[2] & 1)^ (y[2] & 1)); 38 white -= tmp.first, black -= tmp.second; 39 X[0] = max(x[0], x[2]); X[1] = min(x[1], x[3]); 40 Y[0] = max(y[0], y[2]); Y[1] = min(y[1], y[3]); 41 if (X[0] > X[1] || Y[0] > Y[1]) 42 { 43 white += get2(x[1] - x[0], y[1] - y[0]); 44 black += get2(x[3] - x[2], y[3] - y[2]); 45 } 46 else 47 { 48 tmp = get(Y[1] - Y[0], X[1] - X[0], (X[0] & 1) ^ (Y[0] & 1)); 49 white += tmp.first; 50 black += tmp.second; 51 white += get2(x[1] - x[0], y[1] - y[0]) - get2(X[1] - X[0], Y[1] - Y[0]); 52 black += get2(x[3] - x[2], y[3] - y[2]); 53 } 54 printf("%lld %lld\n", white, black); 55 } 56 return 0; 57 }View Code
D. Olya and magical square
Upsolved.
題意:
給出一個$2^n \cdot 2^n 的矩形,每次可以畫一個十字,使得被劃區域的矩形分成四部分,新矩形邊長減半$
$求畫了K刀之後,是否存在左下角矩形到右上角矩形的一條通路,使得經過的矩形邊長都相等$
$如果有,輸出log2(邊長)$
思路:
先考慮最多能畫多少刀
注意到第一次可以畫一刀,第二次可以畫四刀,一共可以畫N次,是一個等比數列
$\frac {4^n - 1}{3}$
暴力去逼近使得 $\frac {4^n - 1}{3} <= k$
這個時候對存在的現有矩形都多畫一刀就要超過k了
那麼我們假設已經畫了$tot刀,我們需要考慮怎麼分配剩下的k - tot 刀$
我們可以保持一個長度為曼哈頓距離的通路,那麼這個通路以外的矩形隨便畫
或者這條通路上的矩形都要畫一次
分類討論一下是否滿足即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 int t; ll n, k; 6 7 bool ok(ll k, ll n, ll tmp) 8 { 9 ll tot = 0; 10 if (k < 0) return false; 11 for (int i = 1; i <= n; ++i) 12 { 13 tot += tmp; 14 tmp *= 4; 15 if (tot >= k) return true; 16 } 17 return false; 18 } 19 20 int ok2(ll k, ll n, ll tmp) 21 { 22 ll tot = 0; 23 for (int i = 1; i <= n; ++i) 24 { 25 tot += tmp; 26 tmp *= 4; 27 if (tot == k) return i; 28 if (tot > k) return -1; 29 } 30 return -1; 31 } 32 33 int main() 34 { 35 scanf("%d", &t); 36 while (t--) 37 { 38 scanf("%lld%lld", &n, &k); 39 ll tot = 0, tmp = 1; int i; 40 for (i = 1; i <= n; ++i) 41 { 42 tot += tmp * tmp; 43 tmp <<= 1; 44 if (tot > k) 45 { 46 --i; 47 tmp >>= 1; 48 tot -= tmp * tmp; 49 break; 50 } 51 else if (tot == k) break; 52 } 53 if (i > n) puts("NO"); 54 else 55 { 56 if (i == n) printf("YES %d\n", 0); 57 else 58 { 59 //cerr << tot << " " << i << " " << tmp << endl; 60 int use; 61 if (ok(k - tot, n - i, tmp * tmp - tmp * 2 + 1)) printf("YES %lld\n", n - i); 62 else if (ok(k - tot - (tmp * 2 - 1), n - i, tmp * tmp - tmp * 2 + 1)) printf("YES %lld\n", n - i - 1); 63 else if ((use = ok2(k - tot, n - i, tmp * 2 - 1)) != -1) printf("YES %lld\n", n - i - use); 64 else puts("NO"); 65 } 66 } 67 } 68 return 0; 69 }View Code
E. Sonya and Matrix Beauty
Upsolved.
題意:
有一個字元矩陣,對於一個子矩陣,對於每一行,可以任意改變字母順序,使得每一行每一列都是迴文串
那麼這個子矩陣就是好矩陣,求有多少個子矩陣是好矩陣
思路:
先考慮一行,一行在改變順序之後是迴文串,那麼其擁有奇數個字母的個數$<= 1$
再來考慮列,如果一個矩陣是好的矩陣
那麼它的第一行中每種字母的個數和最後一行中要相同,第二行要和倒數第二行相同
注意到這和找回文串的思路很像
可以套用Manacher 演算法的思路,$O(26n)處理$
再加上對於行的列舉
總的複雜度為$O(26n^3)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 600 6 int n, m; 7 char s[N][N]; 8 int cnt[N][30]; 9 int Mp[N]; 10 11 bool okone(int x) 12 { 13 int res = 0; 14 for (int i = 0; i < 26; ++i) res += cnt[x][i] & 1; 15 return res <= 1; 16 } 17 18 bool ok(int x, int y) 19 { 20 for (int i = 0; i < 26; ++i) if (cnt[x][i] != cnt[y][i]) 21 return false; 22 return true; 23 } 24 25 int main() 26 { 27 while (scanf("%d%d", &n, &m) != EOF) 28 { 29 n <<= 1; 30 for (int i = 1; i <= n; i += 2) scanf("%s", s[i] + 1); 31 ll res = 0; 32 for (int l = 1; l <= m; ++l) 33 { 34 memset(cnt, 0, sizeof cnt); 35 for (int r = l; r <= m; ++r) 36 { 37 memset(Mp, 0, sizeof Mp); 38 for (int i = 1; i <= n; i += 2) ++cnt[i][s[i][r] - 'a']; 39 int Max = 0, pos = -1; 40 for (int i = 1; i <= n; ++i) 41 { 42 if (!okone(i)) 43 { 44 Mp[i] = 0; 45 continue; 46 } 47 if (Max > i) Mp[i] = min(Mp[2 * pos - i], Max - i); 48 else Mp[i] = 1; 49 while (i >= Mp[i] && i + Mp[i] <= n && okone(i + Mp[i]) && okone(i - Mp[i]) && ok(i + Mp[i], i - Mp[i])) 50 { 51 ++Mp[i]; 52 } 53 if (i + Mp[i] > Max) 54 { 55 Max = i + Mp[i]; 56 pos = i; 57 } 58 res += Mp[i] / 2; 59 } 60 } 61 } 62 printf("%lld\n", res); 63 } 64 return 0; 65 }View Code
F. Katya and Segments Sets
Upsolved.
題意:
有n個集合,每個集合有若干個線段,每次詢問一段連續的集合中,這些集合是否都有至少一條線段被$[l, r] 包含$
思路:
先考慮暴力,我們可以暴力列舉每個集合,所有$y <= r 中對應的x 的最大值是否 >= l$
然後考慮資料結構優化
先按r排序之後,再插入可持久化線段樹之中。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define M 300010 6 #define INF 0x3f3f3f3f 7 int n, q, m, k, brr[M << 1]; 8 struct qnode 9 { 10 int l, r, p; 11 void scan() 12 { 13 scanf("%d%d%d", &l, &r, &p); 14 brr[++m] = r; 15 } 16 bool operator < (const qnode &other) const 17 { 18 return r < other.r; 19 } 20 }qarr[M]; 21 22 int GetHash(int x) { return lower_bound(brr + 1, brr + 1 + m, x) - brr; } 23 void Hash() 24 { 25 sort(brr + 1, brr + 1 + m); 26 m = unique(brr + 1, brr + 1 + m) - brr - 1; 27 for (int i = 1; i <= k; ++i) 28 qarr[i].r = GetHash(qarr[i].r); 29 } 30 31 namespace SEG 32 { 33 int T[M << 1], cnt; 34 struct node 35 { 36 int ls, rs, Min; 37 }a[M * 50]; 38 void build(int &now, int l, int r) 39 { 40 now = ++cnt; 41 a[now].Min = 0; 42 if (l == r) return; 43 int mid = (l + r) >> 1; 44 build(a[now].ls, l, mid); 45 build(a[now].rs, mid + 1, r); 46 } 47 void update(int &now, int pre, int l, int r, int pos, int val) 48 { 49 now = ++cnt; 50 a[now] = a[pre]; 51 if (l == r) 52 { 53 a[now].Min = max(a[now].Min, val); 54 return; 55 } 56 int mid = (l + r) >> 1; 57 if (pos <= mid) update(a[now].ls, a[pre].ls, l, mid, pos, val); 58 else update(a[now].rs, a[pre].rs, mid + 1, r, pos, val); 59 a[now].Min = min(a[a[now].ls].Min, a[a[now].rs].Min); 60 } 61 int query(int now, int l, int r, int ql, int qr) 62 { 63 if (l >= ql && r <= qr) return a[now].Min; 64 int mid = (l + r) >> 1; 65 int res = INF; 66 if (ql <= mid) res = min(res, query(a[now].ls, l, mid, ql, qr)); 67 if (qr > mid) res = min(res, query(a[now].rs, mid + 1, r, ql, qr)); 68 return res; 69 } 70 } 71 72 int main() 73 { 74 while (scanf("%d%d%d", &n, &q, &k) != EOF) 75 { 76 for (int i = 1; i <= k; ++i) qarr[i].scan(); Hash(); 77 sort(qarr + 1, qarr + 1 + k); 78 SEG::build(SEG::T[0], 1, n); 79 for (int i = 1; i <= k; ++i) 80 { 81 if (SEG::T[qarr[i].r] == 0) SEG::T[qarr[i].r] = SEG::T[qarr[i].r - 1]; 82 SEG::update(SEG::T[qarr[i].r], SEG::T[qarr[i].r], 1, n, qarr[i].p, qarr[i].l); 83 } 84 for (int qq = 1, a, b, x, y; qq <= q; ++qq) 85 { 86 scanf("%d%d%d%d", &a, &b, &x, &y); 87 y = upper_bound(brr + 1, brr + 1 + m, y) - brr - 1; 88 int tmp = SEG::query(SEG::T[y], 1, n, a, b); 89 if (tmp >= x) puts("yes"); 90 else puts("no"); 91 if (qq == q) return 0; 92 fflush(stdout); 93 } 94 } 95 return 0; 96 }View Code