其他-学长杂题讲义
1. Rasheda And The Zeriba
大致题意: 给出n条边,判断能否构成一个n边凸多边形,并求出能覆盖该图形的圆的最小半径 1 ≤ n ≤ 1000 。
http://codeforces.com/gym/100283/problem/A
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 5 using namespace std; 6 7 int N; 8 double R[1005]; 9 const double _pi = asin(1)*2; 10 11 bool Check(double v) 12 { 13 double tmp = 0; int i; 14 for (i = 1; i <= N; ++i) 15 if ((tmp += asin(R[i]/2/v)*2) > 2*_pi) break; 16 return i == N+1; 17 } 18 19 int main() 20 { 21 freopen("zeriba.in", "r", stdin); 22 int T; 23 scanf("%d", &T); 24 for (int ca = 1; ca <= T; ++ca) { 25 scanf("%d", &N); 26 double sum = 0, mx = 0; int i; 27 for (i = 1; i <= N; ++i) 28 scanf("%lf", &R[i]), sum += R[i], mx = max(mx, R[i]); 29 for (i = 1; i <= N; ++i) 30 if (sum-R[i] <= R[i]) break; 31 if (i != N+1) { printf("Case %d: can't form a convex polygon\n", ca); continue; } 32 double l = mx/2, r = sum/4; 33 while (fabs(l-r) >= 0.000001) { 34 double mid = (l+r)/2; 35 if (Check(mid)) r = mid; 36 else l = mid; 37 } 38 printf("Case %d: %.4lf\n", ca, l); 39 } 40 return 0; 41 }
2. Fitting boxes
大致题意:给出两个矩形长宽(1 <= x, y, a, b <= 1000),判断能否使其中一个完全覆盖另一个。
http://codeforces.com/gym/100738/problem/A
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 5 const double _PI = asin(1)*2; 6 7 using namespace std; 8 9 inline double P(double v) { return v * v; } 10 11 bool Test(double x, double y, double a, double b) 12 { 13 if (x*y < a*b || a > x) return false; 14 if (b <= y) return true; 15 if (P(y*b) < P(a*a)+P(a*b)-P(a*y)) return false; 16 17 double tmp = _PI/2 - (atan(sqrt(P(y)/(P(a)+P(b)-P(y)))) - atan(a/b)); 18 double tmp2 = b*sin(tmp)+a*cos(tmp); 19 return 0 <= tmp2 && tmp2 <= x; 20 } 21 22 int main() 23 { 24 double t1, t2, t3, t4; 25 int ans = 0; 26 scanf("%lf%lf%lf%lf", &t1, &t2, &t3, &t4); 27 28 ans |= Test(t1, t2, t3, t4); 29 ans |= Test(t1, t2, t4, t3); 30 ans |= Test(t2, t1, t3, t4); 31 ans |= Test(t2, t1, t4, t3); 32 33 swap(t1, t3), swap(t2, t4); 34 35 ans |= Test(t1, t2, t3, t4); 36 ans |= Test(t1, t2, t4, t3); 37 ans |= Test(t2, t1, t3, t4); 38 ans |= Test(t2, t1, t4, t3); 39 40 if (ans) printf("Yes\n"); 41 else printf("No\n"); 42 return 0; 43 }
3. Pretty Buses
大致题意:一个n个点m条边的无向图,每条边有一个权值。初始时,点i处有巴士i和司机i,你可以有两种操作:(1)Drive b x y,把巴士b从x点开到y点并付出这条边的权值的费用;(2)Move d x y,司机d从巴士x移动的巴士y上,没有花费 所有司机要集中在一个点,并且每个司机的换乘次数不多于25 求最小花费,并给出一种合理的方案 1 ≤ n ≤ 200000, 1 ≤ m ≤ 400000
http://codeforces.com/gym/100738/problem/E
#include <cstdio> #include <queue> #include <vector> using namespace std; const int _N = 400005; struct tmpeg { int x, y, w; tmpeg(int x, int y, int w): x(x), y(y), w(w) { } bool operator < (const tmpeg t) const { return w > t.w; } }; priority_queue<tmpeg> Q; vector<int> G[_N], dri[_N]; int veh[_N], siz[_N], Dad[_N]; inline void Ins(int x, int y) { G[x].push_back(y); return; } void diudiu(int node, int dad) { int mx = node; for (int i = G[node].size()-1; i >= 0; --i) { int v = G[node][i]; if (v == dad) continue; diudiu(v, node); printf("Drive %d %d %d\n", veh[v], v, node); int a = veh[node], b = veh[v]; if (siz[a] < siz[b]) swap(a, b); veh[node] = veh[v] = a; siz[a] += siz[b]; for (int j = dri[b].size()-1; j >= 0; --j) { printf("Move %d %d %d\n", dri[b][j], b, a); dri[a].push_back(dri[b][j]), veh[dri[b][j]] = a; } } return; } int GetDad(int v) { return Dad[v] == v ? v : Dad[v] = GetDad(Dad[v]); } int main() { int N, M, i; scanf("%d%d", &N, &M); for (i = 1; i <= M; ++i) { int x, y, w; scanf("%d%d%d", &x, &y, &w); Q.push(tmpeg(x, y, w)); } long long ans = 0; int cnt = 0; for (i = 1; i <= N; ++i) Dad[i] = i, siz[i] = 1, veh[i] = i, dri[i].push_back(i); while (true) { tmpeg tmp = Q.top(); Q.pop(); int tx = GetDad(tmp.x), ty = GetDad(tmp.y); if (tx != ty) { Dad[tx] = ty, Ins(tmp.x, tmp.y), Ins(tmp.y, tmp.x); ++cnt, ans += tmp.w; if (cnt == N-1) break; } } printf("%I64d\n", ans); diudiu(1, 0); printf("Done\n"); return 0; }
4. Mishka and Interesting sum
大致题意:询问数列 A 中 [L, R] 区间出现次数为偶数次的数字,每个数只算一次的异或和。比如对于 {1, 3, 3, 3, 4, 4} ,答案是 1^3^4 。
http://codeforces.com/contest/703/problem/D
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int _N = 1050000; 7 8 struct query { 9 int l, r, id; 10 bool operator < (const query tmp) const 11 { 12 return this->l < tmp.l; 13 } 14 } Q[_N]; 15 16 int pos, N, M, N_A; 17 int A[_N], B[_N], C[_N], sum[_N], fst[_N], nxt[_N], ans[_N]; 18 bool mk[_N]; 19 20 void Add(int k, int d) 21 { 22 for (int i = k; i <= N; i += i & -i) 23 C[i] ^= d; 24 return; 25 } 26 27 int GetSum(int k) 28 { 29 int tmp = 0; 30 for (int i = k; i; i ^= i & -i) 31 tmp ^= C[i]; 32 return tmp; 33 } 34 35 int hs(int v) { return lower_bound(A+1, A+1+N_A, v)-A; } 36 37 int main() 38 { 39 int i; 40 scanf("%d", &N); 41 for (i = 1; i <= N; ++i) 42 scanf("%d", &A[i]), sum[i] = sum[i-1]^A[i], B[i] = A[i]; 43 scanf("%d", &M); 44 for (i = 1; i <= M; ++i) 45 scanf("%d%d", &Q[i].l, &Q[i].r), Q[i].id = i; 46 47 sort(Q+1, Q+1+M); 48 sort(A+1, A+1+N); 49 N_A = unique(A+1, A+1+N)-A-1; 50 for (i = 1; i <= N; ++i) { 51 int tmp; 52 if (!mk[tmp = hs(B[i])]) 53 mk[tmp] = true, Add(i, B[i]); 54 } 55 pos = 1; 56 for (i = N; i >= 1; --i) { 57 int tmp = hs(B[i]); 58 nxt[i] = fst[tmp], fst[tmp] = i; 59 } 60 61 for (i = 1; i <= M; ++i) { 62 while (pos < Q[i].l) { 63 Add(pos, B[pos]); 64 if (nxt[pos]) Add(nxt[pos], B[pos]); 65 ++pos; 66 } 67 ans[Q[i].id] = GetSum(Q[i].r)^sum[Q[i].r]^sum[Q[i].l-1]; 68 } 69 for (i = 1; i <= M; ++i) 70 printf("%d\n", ans[i]); 71 return 0; 72 }
5. Queries
大致题意:维护一个序列,支持 1.单点修改 2.查询某区间 [l, r] 中所有合理的 [i, j] (l <= i <= j <= r) 的异或结果的和。用 Elf(i, j) 表示 [i, j] 中所有数的异或结果,则 [l, r] 查询的结果应为 ∑Elf(i, j) ( [i, j] ⊆ [l, r] ) 。
http://codeforces.com/gym/100739/problem/A
一定注意,尽管根据定义 lsum0(表示左起前缀和中 0 的个数) = 区间长度 - lsum1 (表示左起前缀和中 1 的个数),但是最好在线段树中同时维护这两个变量,这样在查询操作时可以避免一些特判。理论上只记一个变量+特判是可以的,我最初也是这么写的,也就 Wa 了那么七八次吧,还要感谢 newuser 大佬指出我特判的愚蠢性……OrzOrzOrz
1 #include <cstdio> 2 3 const int MOD = 4001; 4 const int _N = 2800000; 5 6 int Tot, N, M; 7 int lsum0[_N], lsum[_N], rsum0[_N], rsum[_N], xos[_N], cnt[_N], lson[_N], rson[_N], root[11]; 8 9 void Modify(int &p, int l, int r, int k, int v) 10 { 11 if (!p) p = ++Tot; 12 if (l == r) { lsum[p] = rsum[p] = cnt[p] = xos[p] = v, lsum0[p] = rsum0[p] = v^1; return; } 13 int mid = l+r >> 1; 14 if (!lson[p]) lson[p] = ++Tot; 15 if (!rson[p]) rson[p] = ++Tot; 16 if (k <= mid) Modify(lson[p], l, mid, k, v); 17 else Modify(rson[p], mid+1, r, k, v); 18 lsum[p] = (lsum[lson[p]] + (xos[lson[p]] ? lsum0[rson[p]] : lsum[rson[p]]))%MOD; 19 rsum[p] = (rsum[rson[p]] + (xos[rson[p]] ? rsum0[lson[p]] : rsum[lson[p]]))%MOD; 20 lsum0[p] = (lsum0[lson[p]] + (xos[lson[p]] ? lsum[rson[p]] : lsum0[rson[p]]))%MOD; 21 rsum0[p] = (rsum0[rson[p]] + (xos[rson[p]] ? rsum[lson[p]] : rsum0[lson[p]]))%MOD; 22 xos[p] = xos[lson[p]] ^ xos[rson[p]]; 23 cnt[p] = (cnt[lson[p]]+cnt[rson[p]])%MOD; 24 cnt[p] = (cnt[p]+rsum[lson[p]]*lsum0[rson[p]]%MOD)%MOD; 25 cnt[p] = (cnt[p]+rsum0[lson[p]]*lsum[rson[p]]%MOD)%MOD; 26 return; 27 } 28 29 int Query(int &p, int l, int r, int s, int t, int &tmp_l, int &tmp_r, int &tmp_x, int &tmp_l0, int &tmp_r0) 30 { 31 if (!p) p = ++Tot; 32 if (s <= l && r <= t) { tmp_l = lsum[p], tmp_r = rsum[p], tmp_x = xos[p], tmp_l0 = lsum0[p], tmp_r0 = rsum0[p]; return cnt[p]; } 33 int mid = l+r >> 1, l_l=0, l_r=0, l_x=0, r_l=0, r_r=0, r_x=0, l_cnt=0, r_cnt=0, l_l0=0, l_r0=0, r_l0=0, r_r0=0; 34 if (t >= l && s <= mid) l_cnt = Query(lson[p], l, mid, s, t, l_l, l_r, l_x, l_l0, l_r0); 35 if (t > mid && s <= r) r_cnt = Query(rson[p], mid+1, r, s, t, r_l, r_r, r_x, r_l0, r_r0); 36 37 tmp_l = (l_l + (l_x ? r_l0 : r_l))%MOD; 38 tmp_r = (r_r + (r_x ? l_r0 : l_r))%MOD; 39 tmp_l0 = (l_l0 + (l_x ? r_l : r_l0))%MOD; 40 tmp_r0 = (r_r0 + (r_x ? l_r : l_r0))%MOD; 41 tmp_x = l_x ^ r_x; 42 int tmp_cnt = (l_cnt+r_cnt)%MOD; 43 tmp_cnt = (tmp_cnt+l_r*r_l0%MOD)%MOD; 44 tmp_cnt = (tmp_cnt+l_r0*r_l%MOD)%MOD; 45 return tmp_cnt; 46 } 47 48 int main() 49 { 50 int i, j; 51 scanf("%d%d", &N, &M); 52 for (i = 1; i <= N; ++i) { 53 int tmp; 54 scanf("%d", &tmp); 55 for (j = 0; j < 11; ++j) 56 Modify(root[j], 1, N, i, (tmp>>j)&1); 57 } 58 while (M--) { 59 int ins, x, y; 60 scanf("%d%d%d", &ins, &x, &y); 61 if (ins == 1) {//change 62 for (j = 0; j < 11; ++j) 63 Modify(root[j], 1, N, x, (y>>j)&1); 64 } else {//query 65 int ans = 0; 66 int tl, tr, tx, tl0, tr0; 67 for (j = 0; j < 11; ++j) 68 ans = (ans+(Query(root[j], 1, N, x, y, tl, tr, tx, tl0, tr0)<<j)%MOD)%MOD; 69 printf("%d\n", (ans+MOD)%MOD); 70 } 71 } 72 return 0; 73 }
6. Decomposition into Good Strings
大致题意:定义 good string 为正好包含 k 种不同字母的字符串(如当 k = 2 时,abbbba 是一个 good string)。给定 k 和一个长为 n (1 <= n <= 200000)的字符串,求该字符串的每个前缀最少可以被分割为多少个 good string 。即输出 n 个数,分别对应原字符串的 n 个前缀的答案。
http://codeforces.com/gym/100971/problem/M
1 #include <cstdio> 2 3 char A[250000]; 4 int f[250000], mk[300], cnt, K, pos; 5 6 void Update(int i) 7 { 8 if (++mk[A[i]] == 1) ++cnt; 9 if (cnt < K) { f[i] = -1; return; } 10 while (cnt > K) { 11 if (!--mk[A[pos]]) --cnt; 12 ++pos; 13 } 14 if (pos == -1) pos = 1; 15 bool flag = false; 16 while (f[pos-1] == -1) { 17 if (mk[A[pos]] == 1) { flag = true; break; } 18 --mk[A[pos]], ++pos; 19 } 20 if (flag) { f[i] = -1; return; } 21 f[i] = f[pos-1]+1; 22 return; 23 } 24 25 int main() 26 { 27 char tt; 28 int i; 29 scanf("%d", &K); 30 f[0] = 0, pos = -1; 31 while ((tt = getchar()) < 'a' || tt > 'z'); 32 A[i = 1] = tt, Update(i); 33 while ((tt = getchar()) >= 'a' && tt <= 'z') 34 A[++i] = tt, Update(i); 35 for (int t = 1; t <= i; ++t) 36 printf("%d ", f[t]); 37 return 0; 38 }