10-30模拟赛

10 / 30 / 2020 | 最后修改于 10 / 30 / 2020

「GCD」

题目描述

我们定义 f(x)f(x) = gcd( xx11 之外的所有因子) 即 xx11 外所有因子的 gcd 询问

f(a)+f(a+1)++f(b)f(a) + f(a+1) + \cdots + f(b)

题解

只有形如 pkp^kff 值才为 pp,其他都是 11 。 线性筛一遍解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Tags:
#include <cstdio>

const int N = 1e7 + 5;
int a, b, cnt, pri[N / 10], val[N];
bool vis[N];

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#else
freopen("T1.in", "r", stdin);
freopen("T1.out", "w", stdout);
#endif
#endif

scanf("%d%d", &a, &b);
for (int i = 2; i <= b; ++i) {
if (!vis[i]) {
pri[++cnt] = i;
long long tmp = i;
while (tmp <= b) {
val[tmp] = i;
tmp *= i;
}
}
for (int j = 1; j <= cnt && pri[j] * i <= b; ++j) {
vis[i * pri[j]] = true;
if (i % pri[j] == 0) break;
}
}
long long ans = 0;
for (int i = a; i <= b; ++i) {
ans += val[i] ? val[i] : 1;
}
printf("%lld", ans);
return 0;
}

「小 A 的同学图」

题目描述

nn 个点,有 mm 条双向道路,每条边都有一个困难程度 wiw_i 。每个点都有一个类型 cic_i 。多次从 xx 出发,每次出发后都会得到一个愉悦值 vv ,为在经过的边权不超过限制时能到达的点的不同种类数个数。每出发一次后限制也会增加 11 。每次询问给出 li,ril_i, r_i 初始限制为 lili ,当限制大于 rir_i 时结束。求获得的愉悦值之和。

题解

我貌似用了个没人用的方法。。。

一看边权有限制,直接想到Kruskal重构树。用bitset维护每个点能到达的种类数,在树上用倍增向上跳就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Tags:
#include <algorithm>
#include <bitset>
#include <cstdio>

typedef long long ll;
const int N = 5e5 + 5, K = 6e2 + 5, BIT = 21;
int n, m, q, x, opt, M, tot, f[N << 1], fa[BIT][N << 1], val[N << 1];
std::bitset<K> bit[N << 1];
ll ans, sum[BIT][N << 1], trash;
int e_cnt, heads[N << 1];

int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }

struct Edge {
int nxt, v, w;
Edge() {}
Edge(int u, int v, int w) : nxt(u), v(v), w(w) {}
inline bool operator<(const Edge &rhs) const { return w < rhs.w; }
} e[N], g[N << 1];

inline void add(int u, int v) {
g[++e_cnt].v = v, g[e_cnt].nxt = heads[u], heads[u] = e_cnt;
}

inline void jump(int &u, int v, ll &res) {
for (int i = BIT - 1; ~i; --i) {
if (val[fa[i][u]] <= v) {
res += sum[i][u];
u = fa[i][u];
}
}
}

void solve(int u) {
for (int i = heads[u], v; i; i = g[i].nxt) {
solve(v = g[i].v);
sum[0][v] = bit[v].count() * (val[u] - val[v]);
}
}

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#else
freopen("T2.in", "r", stdin);
freopen("T2.out", "w", stdout);
#endif
#endif

scanf("%d%d%d%d%d", &n, &m, &q, &x, &opt);
tot = n;
if (opt) { scanf("%d", &M); }
for (int i = 1, c; i <= n; ++i) {
scanf("%d", &c);
bit[i].set(c);
}
for (int i = 1, u, v, w; i <= m; ++i) {
scanf("%d%d%d", &u, &v, &w);
e[i] = Edge(u, v, w);
}
for (register int i = 1, end = n << 1; i <= end; ++i) f[i] = i;
std::sort(e + 1, e + m + 1);
for (int i = 1, u, v; i <= m; ++i) {
if ((u = find(e[i].nxt)) != (v = find(e[i].v))) {
bit[++tot] |= bit[u];
bit[tot] |= bit[v];
val[tot] = e[i].w;
add(tot, u), add(tot, v);
fa[0][u] = tot, fa[0][v] = tot;
fa[0][tot] = tot;
f[u] = f[v] = tot;
}
}

solve(tot);

for (int i = 1, end = n << 1; i < BIT; ++i)
for (int j = 1; j <= end; ++j) {
sum[i][j] = sum[i - 1][j] + sum[i - 1][fa[i - 1][j]];
fa[i][j] = fa[i - 1][fa[i - 1][j]];
}

for (int i = 1, l, r; i <= q; ++i) {
scanf("%d%d", &l, &r);
if (opt) {
l = (l ^ ans) % M + 1;
r = (r ^ ans) % M + 1;
if (l > r) std::swap(l, r);
}
ans = 0;
int cur = x;
jump(cur, l, trash);
if (r < val[fa[0][cur]]) {
ans += (r - l + 1) * bit[cur].count();
} else {
ans += (val[fa[0][cur]] - l) * bit[cur].count();
jump(cur, val[fa[0][cur]], trash);
jump(cur, r, ans);
ans += (r - val[cur] + 1) * bit[cur].count();
}
printf("%lld\n", ans);
}
return 0;
}

「前缀」

题目描述


咕咕咕中