A - 口算训练
题意:询问 $[L, R]$区间内 的所有数的乘积是否是D的倍数
思路:考虑分解质因数
显然,一个数$x > \sqrt{x} 的质因子只有一个$
那么我们考虑将小于$\sqrt {x}$ 的质因子用线段树维护
其他质因子用vector 维护存在性
1 #include2 using namespace std; 3 4 #define N 100010 5 #define block 317 6 vector <int> fac[N], bigfac[10010]; 7 int t, n, q; 8 int arr[N], pos[N], cnt; 9 10 void init() 11 { 12 cnt = 0; 13 memset(pos, 0, sizeof pos); 14 for (int i = 2; i < N; ++i) 15 { 16 if (pos[i] || i > block) continue; 17 for (int j = i * i; j < N; j += i) 18 pos[j] = 1; 19 } 20 for (int i = 2; i < N; ++i) if (!pos[i]) pos[i] = ++cnt; 21 for (int i = 2; i <= 100000; ++i) 22 { 23 int n = i; 24 for (int j = 2; j * j <= n; ++j) 25 { 26 while (n % j == 0) 27 { 28 n = n / j; 29 fac[i].push_back(j); 30 } 31 } 32 if (n != 1) fac[i].push_back(n); 33 sort(fac[i].begin(), fac[i].end()); 34 } 35 } 36 37 int T[80]; 38 struct SEG 39 { 40 #define M N * 300 41 int a[M], lson[M], rson[M], cnt; 42 void init() { cnt = 0; } 43 void pushup(int id) { a[id] = a[lson[id]] + a[rson[id]]; } 44 void update(int &id, int l, int r, int pos) 45 { 46 if (!id) 47 { 48 id = ++cnt; 49 a[id] = lson[id] = rson[id] = 0; 50 } 51 if (l == r) 52 { 53 ++a[id]; 54 return; 55 } 56 int mid = (l + r) >> 1; 57 if (pos <= mid) update(lson[id], l, mid, pos); 58 else update(rson[id], mid + 1, r, pos); 59 pushup(id); 60 } 61 int query(int id, int l, int r, int ql, int qr) 62 { 63 if (!id) return 0; 64 if (l >= ql && r <= qr) return a[id]; 65 int mid = (l + r) >> 1; 66 int res = 0; 67 if (ql <= mid) res += query(lson[id], l, mid, ql, qr); 68 if (qr > mid) res += query(rson[id], mid + 1, r, ql, qr); 69 return res; 70 } 71 }seg; 72 73 bool Get(int base, int need, int l, int r) 74 { 75 // printf("%d %d %d %d\n", base, need, l, r); 76 int have = 0; 77 if (base < block) 78 { 79 have = seg.query(T[pos[base]], 1, n, l, r); 80 if (have < need) return false; 81 } 82 else 83 { 84 have = upper_bound(bigfac[pos[base]].begin(), bigfac[pos[base]].end(), r) - lower_bound(bigfac[pos[base]].begin(), bigfac[pos[base]].end(), l); 85 if (have < need) return false; 86 } 87 return true; 88 } 89 90 bool work(int l, int r, int d) 91 { 92 if (d == 1) return true; 93 int base = fac[d][0], need = 1, have = 0; 94 for (int i = 1, len = fac[d].size(); i < len; ++i) 95 { 96 if (fac[d][i] != base) 97 { 98 if (Get(base, need, l, r) == false) return false; 99 base = fac[d][i]; 100 need = 1; 101 } 102 else ++need; 103 } 104 return Get(base, need, l, r); 105 } 106 107 int main() 108 { 109 init(); 110 scanf("%d", &t); 111 while (t--) 112 { 113 scanf("%d%d", &n, &q); 114 for (int i = 1; i < 10010; ++i) bigfac[i].clear(); 115 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 116 seg.init(); memset(T, 0, sizeof T); 117 for (int i = 1; i <= n; ++i) 118 { 119 for (auto it : fac[arr[i]]) 120 { 121 if (it < block) 122 seg.update(T[pos[it]], 1, n, i); 123 else 124 bigfac[pos[it]].push_back(i); 125 } 126 } 127 for (int i = 1; i <= cnt; ++i) sort(bigfac[i].begin(), bigfac[i].end()); 128 for (int i = 1, l, r, d; i <= q; ++i) 129 { 130 scanf("%d%d%d", &l, &r, &d); 131 puts(work(l, r, d) ? "Yes" : "No"); 132 } 133 } 134 return 0; 135 }
B - 缺失的数据范围
题意:给出$a, b, k$ 求一个最大的n 使得 $n^{a} \cdot log ^b n <= k$
思路:二分 但是要注意用高精度,求log的时候 平方逼近
1 import java.io.BufferedInputStream; 2 import java.util.Scanner; 3 import java.math.*; 4 5 public class Main { 6 7 public static BigInteger Get(BigInteger x, int a, int b) 8 { 9 BigInteger two = BigInteger.valueOf(2); 10 BigInteger tmp = BigInteger.ONE; 11 BigInteger cnt = BigInteger.ZERO; 12 while (tmp.compareTo(x) < 0) 13 { 14 tmp = tmp.multiply(two); 15 cnt = cnt.add(BigInteger.ONE); 16 } 17 BigInteger res = x.pow(a).multiply(cnt.pow(b)); 18 return res; 19 } 20 21 22 public static void main(String[] args) { 23 Scanner in = new Scanner(new BufferedInputStream(System.in)); 24 int t = in.nextInt(); 25 int a, b; BigInteger k, l, r, mid, ans, zero, two, one; 26 zero = BigInteger.ZERO; 27 two = BigInteger.valueOf(2); 28 one = BigInteger.valueOf(1); 29 while (t-- != 0) 30 { 31 a = in.nextInt(); 32 b = in.nextInt(); 33 k = in.nextBigInteger(); 34 l = one; 35 r = k; 36 ans = zero; 37 while (r.subtract(l).compareTo(zero) >= 0) 38 { 39 mid = l.add(r).divide(two); 40 if (Get(mid, a, b).compareTo(k) <= 0) 41 { 42 ans = mid; 43 l = mid.add(one); 44 } 45 else 46 r = mid.subtract(one); 47 } 48 System.out.println(ans); 49 } 50 in.close(); 51 } 52 }
C - 寻宝游戏
留坑。
D - 奢侈的旅行
题意:经过一条路的花费为$log_2^{\frac {level + a_i}{level}}$ 并且 $cost < b_i$ 时不能经过这条路,求$1 -> n$ 的最短路径
思路:考虑等式两边取2的幂次 比如
考虑 $log_2^a + log_2^b = log_2^{ab}$
那么 cost 为
$log_2^{\frac{1 + a_1}{a_1}} + log_2^{\frac {1 + a_1 + a_2}{1 + a_1}} + log_2^{\frac{1 + a_1 + a_2 + a_k}{1 + a_1 + a_2}}$
等价于
$log_2^{1 + a_1 + a_2 + a_k}$
再取2的幂次
$2^{cost} = 2^{log_2 ^{1 + a_1 + a_2 + a_k}}$
1 #include2 using namespace std; 3 4 #define ll long long 5 #define INFLL 0x3f3f3f3f3f3f3f3f 6 #define N 100010 7 int t, n, m; 8 struct Edge { int to; ll a, b; }; 9 vector G[N]; 10 11 struct dnode 12 { 13 int u; ll w; 14 dnode () {} 15 dnode (int u, ll w) : u(u), w(w) {} 16 bool operator < (const dnode &r) const { return w > r.w; } 17 }; 18 19 ll dist[N]; bool used[N]; 20 void Dijkstra() 21 { 22 for (int i = 1; i <= n; ++i) dist[i] = INFLL, used[i] = 0; 23 priority_queue q; q.emplace(1, 1); dist[1] = 1; 24 while (!q.empty()) 25 { 26 int u = q.top().u; q.pop(); 27 if (used[u]) continue; 28 used[u] = 1; 29 for (auto it : G[u]) 30 { 31 int v = it.to; ll a = it.a, b = it.b; 32 if (!used[v] && dist[v] > dist[u] + a && a / dist[u] >= b - 1) 33 { 34 dist[v] = dist[u] + a; 35 q.emplace(v, dist[v]); 36 } 37 38 } 39 } 40 } 41 42 int main() 43 { 44 scanf("%d", &t); 45 while (t--) 46 { 47 scanf("%d%d", &n, &m); 48 for (int i = 1; i <= n; ++i) G[i].clear(); 49 for (int i = 1, u, v, a, b; i <= m; ++i) 50 { 51 scanf("%d%d%d%d", &u, &v, &a, &b); 52 G[u].push_back(Edge{ v, a, 1ll << b}); 53 } 54 Dijkstra(); 55 if (dist[n] == INFLL) puts("-1"); 56 else printf("%lld\n", (ll)(log2(dist[n]))); 57 58 } 59 return 0; 60 }
E - 对称数
题意:找树上一条路径中最小的出现次数为偶数的数
思路:树分块+数字分块 找数字的时候分块统计 $O(1)$更新
好像卡了树上路径莫队。
1 #include2 using namespace std; 3 4 #define N 200010 5 #define block 450 6 #define INF 0x3f3f3f3f 7 int t, n, m; 8 int arr[N]; 9 vector <int> G[N]; 10 int deep[N], fa[N], top[N], son[N], sze[N], cnt; 11 int szeblock[N], Belong[N], dfn[N], dfscnt, dfssize; 12 stack <int> sta; 13 14 void DFS(int u) 15 { 16 dfn[u] = ++dfscnt; 17 sta.push(u); 18 szeblock[u] = 0; 19 sze[u] = 1; 20 for (auto v : G[u]) if (v != fa[u]) 21 { 22 fa[v] = u; 23 deep[v] = deep[u] + 1; 24 DFS(v); sze[u] += sze[v]; szeblock[u] += szeblock[v]; 25 if (son[u] == -1 || sze[v] > sze[son[u]]) son[u] = v; 26 if (szeblock[u] >= block) 27 { 28 szeblock[u] = 0; 29 ++dfssize; 30 while (!sta.empty() && sta.top() != u) { Belong[sta.top()] = dfssize; sta.pop(); } 31 } 32 } 33 ++szeblock[u]; 34 } 35 36 void getpos(int u, int sp) 37 { 38 top[u] = sp; 39 if (son[u] == -1) return; 40 getpos(son[u], sp); 41 for (auto v : G[u]) if (v != son[u] && v != fa[u]) 42 getpos(v, v); 43 } 44 45 int querylca(int u, int v) 46 { 47 int fu = top[u], fv = top[v]; 48 while (fu != fv) 49 { 50 if (deep[fu] < deep[fv]) 51 { 52 swap(fu, fv); 53 swap(u, v); 54 } 55 u = fa[fu]; fu = top[u]; 56 } 57 if (deep[u] > deep[v]) swap(u, v); 58 return u; 59 } 60 61 struct qnode 62 { 63 int u, v, id, lca; 64 qnode() {} 65 qnode(int u, int v, int id, int lca) : u(u), v(v), id(id), lca(lca) {} 66 bool operator < (const qnode &r) const 67 { 68 return Belong[u] == Belong[r.u] ? dfn[v] < dfn[r.v] : Belong[u] < Belong[r.u]; 69 } 70 }que[N]; int ans[N]; 71 72 int used[N], cnt_num[N], num_block[block]; 73 void work(int x) 74 { 75 if (used[x]) --cnt_num[arr[x]]; 76 else ++cnt_num[arr[x]]; 77 num_block[(arr[x] - 1) / block] += 1 * ((cnt_num[arr[x]] & 1) ? 1 : -1); 78 used[x] ^= 1; 79 } 80 81 void update(int u, int v) 82 { 83 while (u != v) 84 { 85 if (deep[u] > deep[v]) swap(u, v); 86 work(v); 87 v = fa[v]; 88 } 89 } 90 91 int Get() 92 { 93 for (int k = 0; k < block; ++k) if (num_block[k] != block) 94 { 95 int l = k * block + 1, r = (k + 1) * block; 96 for (int j = l; j <= r; ++j) if (cnt_num[j] % 2 == 0) 97 return j; 98 } 99 } 100 101 int main() 102 { 103 scanf("%d", &t); 104 while (t--) 105 { 106 scanf("%d%d", &n, &m); 107 memset(son, -1, sizeof son); 108 cnt = 0; dfssize = 0; dfscnt = 0; 109 for (int i = 1; i <= n; ++i) G[i].clear(); 110 memset(num_block, 0, sizeof num_block); 111 memset(cnt_num, 0, sizeof cnt_num); 112 memset(used, 0, sizeof used); 113 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 114 for (int i = 1, u, v; i < n; ++i) 115 { 116 scanf("%d%d", &u, &v); 117 G[u].push_back(v); 118 G[v].push_back(u); 119 } 120 DFS(1); getpos(1, 1); 121 while (!sta.empty()) { Belong[sta.top()] = dfssize; sta.pop();} 122 for (int i = 1, u, v; i <= m; ++i) 123 { 124 scanf("%d%d", &u, &v); 125 if (Belong[u] > Belong[v]) swap(u, v); 126 que[i] = qnode(u, v, i, querylca(u, v)); 127 } 128 //divide on tree 129 sort(que + 1, que + 1 + m); 130 update(que[1].u, que[1].v); 131 work(que[1].lca); 132 ans[que[1].id] = Get(); 133 work(que[1].lca); 134 for (int i = 2; i <= m; ++i) 135 { 136 update(que[i - 1].u, que[i].u); 137 update(que[i - 1].v, que[i].v); 138 work(que[i].lca); 139 ans[que[i].id] = Get(); 140 work(que[i].lca); 141 } 142 for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]); 143 } 144 return 0; 145 }
F - 赛题分析
水。
1 #include2 using namespace std; 3 4 #define N 1010 5 #define INF 0x3f3f3f3f 6 int t, n, m; 7 int arr[N], brr[N]; 8 9 int main() 10 { 11 scanf("%d", &t); 12 for (int kase = 1; kase <= t; ++kase) 13 { 14 printf("Problem %d:\n", kase + 1000); 15 scanf("%d%d", &n, &m); 16 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 17 if (n == 0) puts("Shortest judge solution: N/A bytes."); 18 else printf("Shortest judge solution: %d bytes.\n", *min_element(arr + 1, arr + 1 + n)); 19 for (int i = 1; i <= m; ++i) scanf("%d", brr + i); 20 if (m == 0) puts("Shortest team solution: N/A bytes."); 21 else printf("Shortest team solution: %d bytes.\n", *min_element(brr + 1, brr + 1 + m)); 22 } 23 return 0; 24 }
G - quailty算法
留坑。
H - SA-IS后缀数组
题意:求每对相邻的后缀字符的字典序大小
思路:从后面往前推,只考虑最高位,如果最高位相同,那么问题转化为一个子问题
比如 cm 和 acm 考虑最高位 如果最高位相同 问题转化为 m 和 cm 的大小关系
1 #include2 using namespace std; 3 4 #define N 1000010 5 int t, n; 6 char s[N]; 7 int ans[N]; 8 9 int main() 10 { 11 scanf("%d", &t); 12 while (t--) 13 { 14 int n; 15 scanf("%d%s", &n, s); 16 int len = strlen(s); 17 if (s[len - 1] != s[len - 2]) ans[len - 2] = s[len - 2] > s[len - 1]; 18 else ans[len - 2] = 1; 19 for (int i = len - 3; i >= 0; --i) 20 { 21 if (s[i] != s[i + 1]) ans[i] = s[i] > s[i + 1]; 22 else ans[i] = ans[i + 1]; 23 } 24 for (int i = 0; i < len - 1; ++i) printf("%c", ans[i] ? '>' : '<'); 25 puts(""); 26 } 27 return 0; 28 }
I - 回文树
Upsolved.
因为数据随机,所以答案不会很大,期望为$O(n)级别$ 那么直接考虑暴力枚举,不满足了立即掐掉
可以先排个序,再双指针加速一下
1 #include2 using namespace std; 3 4 #define N 100010 5 #define pii pair 6 int t, n, res, a[N]; 7 vector G[N]; 8 9 void DFS(int fx, int x, int fy, int y) 10 { 11 if (a[x] != a[y]) return; 12 if (fx && x == y) return; 13 if (x <= y) ++res; 14 for (int i = 0, j = 0, k = 0, len = G[x].size(); i < len; ++i) if (G[x][i].second != fx) 15 { 16 while (j < G[y].size() && G[y][j].first < G[x][i].first) ++j; 17 while (k < G[y].size() && G[y][k].first <= G[x][i].first) ++k; 18 for (int o = j; o < k; ++o) if (G[y][0].second != fy) DFS(x, G[x][i].second, y, G[y][o].second); 19 } 20 } 21 22 int main() 23 { 24 scanf("%d", &t); 25 while (t--) 26 { 27 scanf("%d", &n); 28 for (int i = 1; i <= n; ++i) G[i].clear(); 29 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 30 for (int i = 1, u, v; i < n; ++i) 31 { 32 scanf("%d%d", &u, &v); 33 G[u].push_back(pii(a[v], v)); 34 G[v].push_back(pii(a[u], u)); 35 } 36 for (int i = 1; i <= n; ++i) sort(G[i].begin(), G[i].end()); 37 res = 0; 38 for (int i = 1; i <= n; ++i) DFS(0, i, 0, i); 39 for (int i = 1; i <= n; ++i) for (auto it : G[i]) DFS(it.second, i, i, it.second); 40 printf("%d\n", res); 41 } 42 return 0; 43 }
J - 代码派对
留坑。
K - CCPC直播
按题意模拟即可。
1 #include2 using namespace std; 3 4 int t; 5 char s[20], sta[20]; 6 int Rank, x, pro; 7 8 int main() 9 { 10 scanf("%d", &t); 11 while (t--) 12 { 13 scanf("%d%s%d%s", &Rank, s, &pro, sta); 14 printf("%3d|%-16s|%d|[", Rank, s, pro); 15 if (strcmp(sta, "Running") == 0) 16 { 17 scanf("%d", &x); 18 for (int i = 0; i < x; ++i) putchar('X'); 19 for (int i = x; i < 10; ++i) putchar(' '); 20 printf("]\n"); 21 } 22 else 23 { 24 if (strcmp(sta, "FB") == 0) strcpy(sta, "AC*"); 25 printf(" "); 26 printf("%-6s]\n", sta); 27 } 28 } 29 return 0; 30 }