201
edits
(add week 6 contest) |
(update AEFGHIJK) |
||
Line 1: | Line 1: | ||
== Replay == | == Replay == | ||
== Problem A == | https://img-blog.csdnimg.cn/img_convert/ecc6f404c8f1f5c2f0a56f55844d8857.gif | ||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6950 Problem A. Mod, Or and Everything] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组一个整数 <math display="inline">n</math>,求 <math display="inline">(n \; mod \; 1) \; OR \; (n \; mod \; 2) \; OR \; \cdots \; OR \; (n \; mod \; n)</math>. | |||
<math display="inline">1 \leq T \leq 5000, 1 \leq n \leq 10^{12}</math>. | |||
=== 分析 === | |||
<s>分析个啥,直接打表找规律.</s> | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e5; | |||
const int N = (int)1e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)1e9 + 7; | |||
void work() | |||
{ | |||
// for(int i = 1; i <= 100; ++i) | |||
// { | |||
// int s = 0; | |||
// for(int j = 1; j <= i; ++j) s |= i % j; | |||
// printf("%d: %d\n", i, s); | |||
// } | |||
ll n; scanf("%lld", &n); | |||
if(n == 1) | |||
{ | |||
printf("0\n"); | |||
return; | |||
} | |||
for(ll i = 0; ; ++i) | |||
{ | |||
if(((1ll<<i) < n) && n <= ((1ll<<i+1))) | |||
{ | |||
printf("%lld\n", (1ll<<i) - 1); | |||
break; | |||
} | |||
} | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
return 0; | |||
}</syntaxhighlight> | |||
[https://acm.hdu.edu.cn/showproblem.php?pid=6951 Problem B. Rocket land] | |||
[https://acm.hdu.edu.cn/showproblem.php?pid=6952 Problem C. Puzzle loop] | |||
[https://acm.hdu.edu.cn/showproblem.php?pid=6953 Problem D. Another thief in a Shop] | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6954 Problem E. Minimum spanning tree] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组给出一个 <math display="inline">n</math>. | |||
点的编号为 <math display="inline">1, 2, \cdots, n</math>,点 <math display="inline">a</math> 与 点 <math display="inline">b</math> 的权值定义为 <math display="inline">lcm(a, b)</math>. | |||
求这个图的最小生成树. | |||
<math display="inline">1 \leq T \leq 10^2, 2 \leq n \leq 10^7</math>. | |||
=== 分析 === | |||
显然合数与它的因子连边,质数与 <math display="inline">2</math> 连边最优. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e7; | |||
const int N = (int)1e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)1e9 + 7; | |||
int cnt, prime[M + 5]; | |||
bool is_prime[M + 5]; | |||
ll f[M + 5]; | |||
void init() | |||
{ | |||
memset(is_prime, 1, sizeof(is_prime)); | |||
cnt = is_prime[0] = is_prime[1] = 0; | |||
for(int i = 2; i <= M; ++i) | |||
{ | |||
if(is_prime[i]) prime[++cnt] = i; | |||
for(int j = 1; j <= cnt && i * prime[j] <= M; ++j) | |||
{ | |||
is_prime[i * prime[j]] = 0; | |||
if(i % prime[j] == 0) break; | |||
} | |||
} | |||
f[2] = 0; | |||
for(int i = 3; i <= M; ++i) | |||
{ | |||
if(is_prime[i]) f[i] = f[i - 1] + 2 * i; | |||
else f[i] = f[i - 1] + i; | |||
} | |||
} | |||
void work() | |||
{ | |||
int n; scanf("%d", &n); | |||
printf("%lld\n", f[n]); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
init(); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6955 Problem F. Xor sum] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组输入有两个整数 <math display="inline">n</math> 和 <math display="inline">k</math>,接下来 <math display="inline">n</math> 个整数表示 <math display="inline">a[1], a[2], \cdots, a[n]</math>. | |||
要求找一段区间,使得这段区间的异或和不小于 <math display="inline">k</math>,若不存在则输出 <math display="inline">-1</math>,存在则找到满足上述条件最短的区间,若仍不唯一,则输出最靠左的区间. | |||
<math display="inline">1 \leq T \leq 10^2, 1 \leq n \leq10^5, 0 \leq k, a[i] < 2^{30}</math>. | |||
=== 分析 === | |||
记 <math display="inline">s[i] = a[1] \; XOR \; a[2] \; XOR \; \cdots \; XOR \;a[i]</math>. | |||
则区间 <math display="inline">[l, r]</math> 异或和不小于 <math display="inline">k</math> 等价于 <math display="inline">s[r] \; XOR \; s[l-1]</math> 不小于 <math display="inline">k</math>. | |||
因此字典树维护 <math display="inline">s[i]</math>,节点记录当前最新的时间戳,对于两边都能走的情况就选择最新的时间戳走. | |||
详见代码. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e5; | |||
const int N = (int)29; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)1e9 + 7; | |||
struct tnode | |||
{ | |||
int nx[2], stamp; | |||
} tree[M * 31 + 5]; | |||
int cnt; | |||
int n, k; | |||
void insert(int p, int d, int x, int stamp) | |||
{ | |||
if(d == -1) return; | |||
int v = (x>>d&1); | |||
if(!tree[p].nx[v]) | |||
{ | |||
tree[p].nx[v] = ++cnt; | |||
tree[tree[p].nx[v]].nx[0] = 0; | |||
tree[tree[p].nx[v]].nx[1] = 0; | |||
tree[tree[p].nx[v]].stamp = 0; | |||
} | |||
tree[p].stamp = stamp; | |||
insert(tree[p].nx[v], d - 1, x, stamp); | |||
if(d == 0) | |||
{ | |||
tree[tree[p].nx[v]].stamp = stamp; | |||
} | |||
} | |||
inline int setZero(int x, int k) | |||
{ | |||
return x&(~(1<<k)); | |||
} | |||
inline int setOne(int x, int k) | |||
{ | |||
return x|(1<<k); | |||
} | |||
int queryMx(int x, int p, int d) | |||
{ | |||
for(int i = d, v; i >= 0; --i) | |||
{ | |||
v = (x>>i&1); | |||
if(tree[p].nx[!v]) p = tree[p].nx[!v], x = setOne(x, i); | |||
else p = tree[p].nx[v], x = setZero(x, i); | |||
} | |||
return x; | |||
} | |||
int mi, l, r; | |||
void query(int x, int stamp, bool f = 0) | |||
{ | |||
int p = 0; | |||
for(int i = N, vk, vx; i >= 0; --i) | |||
{ | |||
vk = (k>>i&1); | |||
vx = (x>>i&1); | |||
bool canZero = 0, canOne = 0; | |||
if(tree[p].nx[vx]) canZero = queryMx(setZero(x, i), tree[p].nx[vx], i - 1) >= k; | |||
if(tree[p].nx[!vx]) canOne = queryMx(setOne(x, i), tree[p].nx[!vx], i - 1) >= k; | |||
if(canZero && canOne) | |||
{ | |||
if(tree[tree[p].nx[vx]].stamp > tree[tree[p].nx[!vx]].stamp) p = tree[p].nx[vx], x = setZero(x, i); | |||
else p = tree[p].nx[!vx], x = setOne(x, i); | |||
} | |||
else if(canZero) p = tree[p].nx[vx], x = setZero(x, i); | |||
else if(canOne) p = tree[p].nx[!vx], x = setOne(x, i); | |||
else return; | |||
} | |||
if(mi > stamp - tree[p].stamp) | |||
{ | |||
mi = stamp - tree[p].stamp; | |||
l = tree[p].stamp + 1, r = stamp; | |||
} | |||
} | |||
void work() | |||
{ | |||
mi = inf, l = -1, r = -1; | |||
cnt = tree[0].nx[0] = tree[0].nx[1] = tree[0].stamp = 0; | |||
scanf("%d %d", &n, &k); | |||
insert(0, N, 0, 0); | |||
int s = 0; | |||
for(int i = 1, a; i <= n; ++i) | |||
{ | |||
scanf("%d", &a); | |||
s ^= a; | |||
query(s, i); | |||
insert(0, N, s, i); | |||
} | |||
if(mi == inf) printf("-1\n"); | |||
else printf("%d %d\n", l, r); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6956 Problem G. Pass!] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组有两个整数 <math display="inline">n</math> 和 <math display="inline">x</math>. | |||
一共有 <math display="inline">n</math> 个人和 <math display="inline">1</math> 个球,初始球在第 <math display="inline">1</math> 人脚下,每秒拥有球的那个人会把球传给另一个人. | |||
经过 <math display="inline">t</math> 秒后,球又回到了第 <math display="inline">1</math> 个人脚下,方案数为 <math display="inline">x</math>. | |||
现在给出 <math display="inline">x</math> 要求反解最小非负整数 <math display="inline">t</math>. | |||
=== 分析 === | |||
设 <math display="inline">f[i][0]</math> 表示第 <math display="inline">i</math> 秒末球不在第 <math display="inline">1</math> 个人脚下的方案数,<br /> | |||
<math display="inline">\quad f[i][1]</math> 表示第 <math display="inline">i</math> 秒末球在第 <math display="inline">1</math> 个人脚下的方案数. | |||
则有如下转移方程: | |||
<math display="block">\left\{ | |||
\begin{aligned} | |||
f[0][1] &= 1 \\ | |||
f[i][0] &= (n - 2)f[i - 1][0] + (n - 1)f[i - 1][1] \\ | |||
f[i][1] &= f[i - 1][0] | |||
\end{aligned} | |||
\right. | |||
\rightarrow | |||
\left\{ | |||
\begin{aligned} | |||
f[1][0] &= n - 1 \\ | |||
f[2][0] &= (n - 1)(n - 2) \\ | |||
f[i][0] &= (n - 2)f[i - 1][0] + (n - 1)f[i - 2][0] \quad i \geq 3\\ | |||
\end{aligned} | |||
\right.</math> | |||
学了一下[https://zhuanlan.zhihu.com/p/104596563 二阶线性递推式的通项求法],<s>夙愿清单减减.</s> | |||
于是可以得到 <math display="inline">f[i][0]</math> 的解析式为 <math display="inline">f[i][0] = \frac{(n -1)^2}{n}(n-1)^{i - 1} + \frac{n - 1}{n}(-1)^{i - 1}</math>. | |||
又由 <math display="inline">f[i][1] = f[i - 1][0]</math> 得 | |||
<math display="block">\begin{aligned} | |||
f[i][1] &= f[i - 1][0] \\ | |||
&= \frac{(n -1)^2}{n}(n-1)^{i - 2} + \frac{n - 1}{n}(-1)^{i - 2} \quad i \geq 0 \\ | |||
&= | |||
\left\{ | |||
\begin{aligned} | |||
\frac{(n -1)^i}{n} &- \frac{n - 1}{n} \quad i \; is \; odd \\ | |||
\frac{(n -1)^i}{n} &+ \frac{n - 1}{n} \quad i \; is \; even \\ | |||
\end{aligned} | |||
\right. \\ | |||
&= | |||
\left\{ | |||
\begin{aligned} | |||
\frac{(n -1)^{2k+1}}{n} &- \frac{n - 1}{n} \quad i = 2k+1, k \geq 0\\ | |||
\frac{(n -1)^{2k}}{n} &+ \frac{n - 1}{n} \quad i = 2k, k \geq 0\\ | |||
\end{aligned} | |||
\right. \\ | |||
&\stackrel{Only \; need \; to \; solve}{\longrightarrow} | |||
\left\{ | |||
\begin{aligned} | |||
(n-1)^{2k} &\equiv \frac{nx + n - 1}{n - 1} \; (mod\; p) \\ | |||
(n-1)^{2k} &\equiv nx - n + 1\; (mod \; p) \\ | |||
\end{aligned} | |||
\right. \\ | |||
\end{aligned}</math> | |||
至此套上 BSGS 即可. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e5; | |||
const int N = (int)1e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)998244353; | |||
struct hashTable | |||
{ | |||
const static int M = (int)1e5; | |||
const static int N = (int)31601; | |||
int head[N + 5], cnt; | |||
struct node | |||
{ | |||
int v, w, nx; | |||
} a[M + 5]; | |||
void init() | |||
{ | |||
cnt = 0; | |||
memset(head, -1, sizeof(head)); | |||
} | |||
void add(int v, int w) | |||
{ | |||
for(int i = head[w % N]; ~i; i = a[i].nx) | |||
{ | |||
if(a[i].w == w) | |||
{ | |||
a[i].v = v; | |||
return; | |||
} | |||
} | |||
a[cnt].v = v; | |||
a[cnt].w = w; | |||
a[cnt].nx = head[w % N]; | |||
head[w % N] = cnt++; | |||
} | |||
int tofind(int w) | |||
{ | |||
for(int i = head[w % N]; ~i; i = a[i].nx) | |||
{ | |||
if(a[i].w == w) return a[i].v; | |||
} | |||
return -1; | |||
} | |||
} H; | |||
struct LOG | |||
{ | |||
ll quick(ll a, ll b, ll p = mod) | |||
{ | |||
ll s = 1; | |||
while(b) | |||
{ | |||
if(b & 1) s = s * a % p; | |||
a = a * a % p; | |||
b >>= 1; | |||
} | |||
return s; | |||
} | |||
ll inv(ll n, ll p = mod) | |||
{ | |||
return quick(n, p - 2, p); | |||
} | |||
int k = 31596, t; | |||
void init(int a, int p) | |||
{ | |||
H.init(); | |||
for(int i = 0, j = 1; i < k; ++i) | |||
{ | |||
H.add(i, j); | |||
j = 1ll * j * a % p; | |||
} | |||
t = quick(a, k, p); | |||
} | |||
int BSGS(int a, int b, int p) | |||
{ | |||
a = (1ll * a % p + p) % p, b = (1ll * b % p + p) % p; | |||
if(b == 1) return 0; | |||
for(int i = 1, j = t * inv(b, p) % p, h; i <= k; ++i) | |||
{ | |||
h = H.tofind(j); | |||
if(~h && 1ll * k * i > h && !((1ll * k * i - h)&1)) return 1ll * k * i - h; | |||
j = 1ll * j * t % p; | |||
} | |||
return -1; | |||
} | |||
} B; | |||
int n, x; | |||
int calOdd() | |||
{ | |||
int a = (1ll * n * x % mod + n - 1 + mod) % mod * B.inv(n - 1) % mod; | |||
int x = B.BSGS(n - 1, a, mod); | |||
if(x == -1) return inf; | |||
return x + 1; | |||
} | |||
int calEven() | |||
{ | |||
int a = (1ll * n * x % mod - n + 1 + mod) % mod; | |||
int x = B.BSGS(n - 1, a, mod); | |||
if(x == -1) return inf; | |||
return x; | |||
} | |||
void work() | |||
{ | |||
scanf("%d %d", &n, &x); | |||
B.init(n - 1, mod); | |||
int odd = calOdd(), even = calEven(); | |||
int mi = min(odd ,even); | |||
if(mi == inf) printf("-1\n"); | |||
else printf("%d\n", mi); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
// cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n"; | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6957 Problem H. Maximal submatrix] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组输入一个 <math display="inline">n \times m</math> 的矩阵. | |||
求一个最大子矩阵,这个子矩阵每一列中的元素递增,输出最大子矩阵的大小. | |||
<math display="inline">1 \leq T \leq 10, 1 \leq n, m \leq 2000</math>. | |||
=== 分析 === | |||
单调栈经典题了. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)2e3; | |||
const int N = (int)1e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)1e9 + 7; | |||
int n, m; | |||
int a[M + 5][M + 5]; | |||
int b[M + 5][M + 5]; | |||
int s[M + 5], w[M + 5], p; | |||
int cal(int a[]) | |||
{ | |||
a[m + 1] = p = 0; | |||
int ans = 0; | |||
for(int i = 1; i <= m + 1; ++i) | |||
{ | |||
if(a[i] > s[p]) | |||
{ | |||
s[++p] = a[i], w[p] = 1; | |||
} | |||
else | |||
{ | |||
int width = 0; | |||
while(s[p] > a[i]) | |||
{ | |||
width += w[p]; | |||
ans = max(ans, width * s[p]); | |||
p--; | |||
} | |||
s[++p] = a[i], w[p] = width + 1; | |||
} | |||
} | |||
return ans; | |||
} | |||
void work() | |||
{ | |||
scanf("%d %d", &n, &m); | |||
for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]); | |||
for(int j = 1; j <= m; ++j) | |||
{ | |||
b[1][j] = 1; | |||
for(int i = 2; i <= n; ++i) | |||
{ | |||
if(a[i][j] >= a[i - 1][j]) b[i][j] = b[i - 1][j] + 1; | |||
else b[i][j] = 1; | |||
} | |||
} | |||
int mx = 0; | |||
for(int i = 1; i <= n; ++i) | |||
{ | |||
mx = max(mx, cal(b[i])); | |||
} | |||
printf("%d\n", mx); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6958 Problem I. KD-Graph] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组输入 <math display="inline">n, m, k</math> 表示 <math display="inline">n</math> 个点 <math display="inline">m</math> 条边的有权联通无向图. | |||
接下来 <math display="inline">m</math> 行,每行三个整数 <math display="inline">u, v, w</math> 表示无向边的两个端点和边权. | |||
一个图被称为 KD 图当且仅当 <math display="inline">n</math> 个点可以不重不漏地分成 <math display="inline">K</math> 组且组内两两点之间存在一条路径,满足这条路径的最大边权小于等于 <math display="inline">D</math>,不同组的每两点则不存在这样的路径. | |||
要求计算最小的非负整数 <math display="inline">D</math>,若不存在输出 <math display="inline">-1</math>. | |||
=== 分析 === | |||
赛时一开始二分 + BFS,结果 TLE... | |||
换成二分 + 并查集,常数小了点,得到 AC. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
#pragma GCC optimize(2) | |||
using namespace std; | |||
inline int read() | |||
{ | |||
int x = 0, f = 1; | |||
char ch = getchar(); | |||
while(!isdigit(ch)) | |||
{ | |||
if(ch == '-') f = -1; | |||
ch = getchar(); | |||
} | |||
while(isdigit(ch)) | |||
{ | |||
x = x * 10 + ch - '0'; | |||
ch = getchar(); | |||
} | |||
return x * f; | |||
} | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e5; | |||
const int N = (int)5e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)1e9 + 7; | |||
int n, m, k; | |||
struct enode | |||
{ | |||
int u, v, w; | |||
} Edge[N + 5]; | |||
int fa[M + 5]; | |||
int rk[M + 5]; | |||
int tofind(int x) | |||
{ | |||
if(x == fa[x]) return x; | |||
return fa[x] = tofind(fa[x]); | |||
} | |||
int cal(int lim) | |||
{ | |||
for(int i = 1; i <= n; ++i) fa[i] = i; | |||
for(int i = 1, u, v; i <= m; ++i) | |||
{ | |||
u = Edge[i].u, v = Edge[i].v; | |||
if(Edge[i].w <= lim) | |||
{ | |||
u = tofind(u), v = tofind(v); | |||
if(u != v) | |||
{ | |||
if(rk[u] > rk[v]) swap(u, v); | |||
fa[u] = v, rk[v] = max(rk[v], rk[u] + 1); | |||
} | |||
} | |||
} | |||
int cnt = 0; | |||
for(int i = 1; i <= n; ++i) if(fa[i] == i) ++cnt; | |||
return cnt; | |||
} | |||
void work() | |||
{ | |||
n = read(), m = read(), k = read(); | |||
int l = 0, r = 0, mid; | |||
for(int i = 1; i <= m; ++i) | |||
{ | |||
Edge[i].u = read(), Edge[i].v = read(), Edge[i].w = read(); | |||
r = max(r, Edge[i].w); | |||
} | |||
while(l < r) | |||
{ | |||
mid = (l + r) >> 1; | |||
if(cal(mid) <= k) r = mid; | |||
else l = mid + 1; | |||
} | |||
if(cal(r) == k) printf("%d\n", r); | |||
else printf("-1\n"); | |||
} | |||
int main() | |||
{ | |||
// cout << 5 * log2(inf) * (M + 2 * N) << "\n"; | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T = read(); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
// cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n"; | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6959 Problem J. zoto] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组输入 <math display="inline">n, m</math> 表示二维平面上有 <math display="inline">n</math> 个整数点和 <math display="inline">m</math> 次询问. | |||
接下来 <math display="inline">n</math> 行,每行一个非负整数 <math display="inline">fx[i]</math>,表示有一个整数点 <math display="inline">(i, fx[i])</math>. | |||
接下来 <math display="inline">m</math> 行,每行四个整数 <math display="inline">x0, y0, x1, y1</math> 表示查询 <math display="inline">(x0, y0)</math> 与 <math display="inline">(x1, y1)</math> 围成的矩阵里有多少个不同的 <math display="inline">y</math> 值. | |||
<math display="inline">1 \leq T \leq 5, 1 \leq n, m, x0, x1 \leq 10^5, 0 \leq fx[i], y0, y1 \leq 10^5</math>. | |||
=== 分析 === | |||
一开始用莫队 + 线段树喜提 TLE. | |||
正解是莫队 + 分块. | |||
分块支持 <math display="inline">O(1)</math> 修改 + <math display="inline">O(\sqrt{10^5})</math> 查询. | |||
'''小收获:莫队的修改次数很多,查询次数较少,应选择修改较快的数据结构进行维护.''' | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
inline int read() | |||
{ | |||
int x = 0, f = 1; | |||
char ch = getchar(); | |||
while(!isdigit(ch)) | |||
{ | |||
if(ch == '-') f = -1; | |||
ch = getchar(); | |||
} | |||
while(isdigit(ch)) | |||
{ | |||
x = x * 10 + ch - '0'; | |||
ch = getchar(); | |||
} | |||
return x * f; | |||
} | |||
void print(int n) | |||
{ | |||
if(n < 0) | |||
{ | |||
putchar('-'); | |||
print(-n); | |||
} | |||
else | |||
{ | |||
if(n > 9) print(n / 10); | |||
putchar(n % 10 + '0'); | |||
} | |||
} | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e5; | |||
const int N = (int)320; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)998244353; | |||
int n, m, xblock, yblock, yblockCnt; | |||
int a[M + 5]; | |||
int ans[M + 5]; | |||
struct qnode | |||
{ | |||
int l, r, a, b, id; | |||
bool operator<(const qnode& b)const | |||
{ | |||
return l / xblock == b.l / xblock ? (r == b.r ? 0 : ((l / xblock) & 1) ^ (r < b.r)) : l < b.l; | |||
} | |||
} q[M + 5]; | |||
int id[M + 5]; | |||
int num[M + 5]; | |||
int nums[N + 5]; | |||
int mx; | |||
void init() | |||
{ | |||
yblock = (int)sqrt(mx), yblockCnt = (mx + yblock) / yblock; | |||
for(int i = 0; i <= mx; ++i) | |||
{ | |||
id[i] = i / yblock; | |||
num[i] = 0; | |||
} | |||
for(int i = 0; i < yblockCnt; ++i) nums[i] = 0; | |||
} | |||
void add(int x) | |||
{ | |||
if(++num[a[x]] == 1) ++nums[id[a[x]]]; | |||
} | |||
void del(int x) | |||
{ | |||
if(--num[a[x]] == 0) --nums[id[a[x]]]; | |||
} | |||
int query(int l, int r) | |||
{ | |||
int ans = 0; | |||
if(id[r] - id[l] + 1 <= 2) | |||
{ | |||
for(int i = l; i <= r; ++i) if(num[i]) ++ans; | |||
} | |||
else | |||
{ | |||
for(int i = l; i <= n && id[i] == id[l]; ++i) if(num[i]) ++ans; | |||
for(int i = r; i >= 1 && id[i] == id[r]; --i) if(num[i]) ++ans; | |||
for(int i = id[l] + 1; i < id[r]; ++i) ans += nums[i]; | |||
} | |||
return ans; | |||
} | |||
void work() | |||
{ | |||
n = read(), m = read(); xblock = (int)sqrt(n); | |||
for(int i = 1; i <= n; ++i) a[i] = read(); | |||
mx = 1; | |||
for(int i = 1; i <= m; ++i) | |||
{ | |||
q[i].l = read(), q[i].a = read(), q[i].r = read(), q[i].b = read(); | |||
mx = max(mx, q[i].b); | |||
q[i].id = i; | |||
} | |||
init(); | |||
sort(q + 1, q + m + 1); | |||
int l = 1, r = 0; | |||
for(int i = 1; i <= m; ++i) | |||
{ | |||
while(r < q[i].r) add(++r); | |||
while(r > q[i].r) del(r--); | |||
while(l < q[i].l) del(l++); | |||
while(l > q[i].l) add(--l); | |||
ans[q[i].id] = query(q[i].a, q[i].b); | |||
} | |||
for(int i = 1; i <= m; ++i) print(ans[i]), putchar('\n'); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
// cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n"; | |||
return 0; | |||
}</syntaxhighlight> | |||
== [https://acm.hdu.edu.cn/showproblem.php?pid=6960 Problem K. Necklace of Beads] == | |||
=== 题目大意 === | |||
<math display="inline">T</math> 组输入,每组给出 <math display="inline">n</math> 和 <math display="inline">k</math>. | |||
有红蓝绿三种颜色的珠子,红蓝珠子有无穷多个,绿色珠子只有 <math display="inline">k</math> 个,要求串成 <math display="inline">n</math> 个珠子的项链. | |||
两个项链如果可以通过旋转得到则认为是一种方案. | |||
求方案数. | |||
<math display="inline">1 \leq T \leq 10, 1 \leq n, k \leq 10^6</math>. | |||
=== 分析 === | |||
显然Burnside 引理,于是 | |||
<math display="block">\begin{aligned} | |||
ANS &= \frac{1}{n}\sum_{i=0}^{n - 1}{\sum_{j=0}^{\lfloor \frac{k}{n/gcd(n, i)} \rfloor}{f(gcd(n, i), j)}} \\ | |||
&= \frac{1}{n}\sum_{d=1}^{n}{\varphi(\frac{n}{d})\sum_{j=0}^{\lfloor \frac{k}{n/d} \rfloor}{f(d, j)}} | |||
\end{aligned}</math> | |||
<math display="inline">f(n, m)</math> 表示长度为 <math display="inline">n</math> 的环,绿色珠子有 <math display="inline">m</math> 个的合法方案数. | |||
<math display="inline">g(n, m)</math> 表示长度为 <math display="inline">n</math> 的序列,选 <math display="inline">m</math> 个互不相邻位置的方案数. | |||
对绿色珠子的位置分类讨论: | |||
# 假设绿色珠子放在 <math display="inline">1</math> 号位置,则 <math display="inline">2, n</math> 这两个位置不能放绿色珠子,并且绿色珠子把环分割为 <math display="inline">m</math> 段,每段的方案数为 <math display="inline">2</math>,因此总方案数为 <math display="inline">g(n - 3, m - 1) \times 2^{m}</math>. | |||
# 假设绿色珠子放在 <math display="inline">n</math> 号位置,根据对称性,方案数同 <math display="inline">1.</math> | |||
# 除上述两种情况之外,方案数为 <math display="inline">g(n - 2, m) \times 2^{m}</math>. | |||
因此 <math display="inline">f(n, m) = g(n - 3, m - 1) \times 2^{m+1} + g(n - 2, m) \times 2^{m}</math>. | |||
由插空法可得 <math display="inline">g(n, m) = \binom{n - m + 1}{m}</math>. | |||
<math display="inline">O(10^6)</math> 预处理出欧拉函数和阶乘,逆元,阶乘逆元. | |||
时间复杂度 <math display="inline">O(10^6 + T\sqrt{n})</math>. | |||
=== 代码实现 === | |||
<syntaxhighlight lang="cpp">#include <bits/stdc++.h> | |||
using namespace std; | |||
typedef long long ll; | |||
typedef unsigned long long ull; | |||
const int M = (int)1e6; | |||
const int N = (int)1e5; | |||
const double eps = 1e-6; | |||
const int inf = 0x3f3f3f3f; | |||
const ll mod = (ll)998244353; | |||
bool is_prime[M + 5]; | |||
int cnt, prime[M + 5]; | |||
int phi[M + 5]; | |||
int fac[M + 5], inv[M + 5], invfac[M + 5]; | |||
void init() | |||
{ | |||
phi[1] = 1; | |||
memset(is_prime, 1, sizeof(is_prime)); | |||
cnt = is_prime[0] = is_prime[1] = 0; | |||
fac[0] = fac[1] = inv[1] = invfac[0] = invfac[1] = 1; | |||
for(int i = 2; i <= M; ++i) | |||
{ | |||
fac[i] = 1ll * fac[i - 1] * i % mod; | |||
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod; | |||
invfac[i] = 1ll * invfac[i - 1] * inv[i] % mod; | |||
if(is_prime[i]) | |||
{ | |||
prime[++cnt] = i; | |||
phi[i] = i - 1; | |||
} | |||
for(int j = 1; j <= cnt && i * prime[j] <= M; ++j) | |||
{ | |||
is_prime[i * prime[j]] = 0; | |||
if(i % prime[j] == 0) | |||
{ | |||
phi[i * prime[j]] = phi[i] * prime[j]; | |||
break; | |||
} | |||
phi[i * prime[j]] = phi[i] * (prime[j] - 1); | |||
} | |||
} | |||
} | |||
int c(int n, int m) | |||
{ | |||
if(n < 0 || m < 0 || n < m) return 0; | |||
return 1ll * fac[n] * invfac[m] % mod * invfac[n - m] % mod; | |||
} | |||
void work() | |||
{ | |||
int n, k; scanf("%d %d", &n, &k); | |||
int ans = 0; | |||
for(int d = 1, two, r, f, dd; 1ll * d * d <= n; ++d) | |||
{ | |||
if(n % d) continue; | |||
two = 1, r = 1ll * k * d / n, f = (!(d&1)) * 2; | |||
for(int j = 1; j <= r; ++j) | |||
{ | |||
two = 2ll * two% mod; | |||
f = (f + 2ll * two * c(d - j - 1, j - 1) + 1ll * two * c(d - j - 1, j)) % mod; | |||
} | |||
ans = (ans + 1ll * f * phi[n / d]) % mod; | |||
if(d * d == n) continue; | |||
dd = n / d; | |||
two = 1, r = 1ll * k * dd / n, f = (!(dd&1)) * 2; | |||
for(int j = 1; j <= r; ++j) | |||
{ | |||
two = 2ll * two% mod; | |||
f = (f + 2ll * two * c(dd - j - 1, j - 1) + 1ll * two * c(dd - j - 1, j)) % mod; | |||
} | |||
ans = (ans + 1ll * f * phi[n / dd]) % mod; | |||
} | |||
ans = 1ll * ans * inv[n] % mod; | |||
printf("%d\n", ans); | |||
} | |||
int main() | |||
{ | |||
// freopen("input.txt", "r", stdin); | |||
// freopen("output.txt", "w", stdout); | |||
// ios::sync_with_stdio(0); | |||
// cin.tie(0); cout.tie(0); | |||
init(); | |||
int T; scanf("%d", &T); | |||
for(int ca = 1; ca <= T; ++ca) | |||
{ | |||
// printf("Case #%d:\n", ca); | |||
work(); | |||
} | |||
// work(); | |||
// cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n"; | |||
return 0; | |||
}</syntaxhighlight> |