概述
比赛链接
点击打开链接
官方题解
点击打开链接
Problem A. 01 Matrix
将子矩阵 [ 1 , B ] × [ 1 , A ] [1,B]times[1,A] [1,B]×[1,A] 和 [ B + 1 , H ] × [ A + 1 , W ] [B+1,H]times[A+1,W] [B+1,H]×[A+1,W] 标为 1 1 1 ,剩余部分标为 0 0 0 即可。
时间复杂度 O ( H × W ) O(Htimes W) O(H×W) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int main() {
int n, m, a, b;
read(n), read(m), read(a), read(b);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
if (i <= b && j <= a) putchar('1');
else if (i > b && j > a) putchar('1');
else putchar('0');
puts("");
}
return 0;
}
Problem B. Sorting a Segment
考虑排序后的结果,若所排序的区间原本就是有序的,那么得到的序列就是原序列,所有排序有序区间的方案对应的结果是相同的。
否则,一定改变了某些元素的位置,不难发现若排序 [ i , i + k ) [i,i+k) [i,i+k) 的结果和排序 [ j , j + k ) [j,j+k) [j,j+k) 的结果一样,那么排序 [ i , i + k ) , [ i + 1 , i + 1 + k ) , [ i + 2 , i + 2 + k ) , … , [ j , j + k ) [i,i+k),[i+1,i+1+k),[i+2,i+2+k),dots,[j,j+k) [i,i+k),[i+1,i+1+k),[i+2,i+2+k),…,[j,j+k) 的结果也一样,因此我们只需要统计排序 [ i − 1 , i − 1 + k ) , [ i , i + k ) [i-1,i-1+k),[i,i+k) [i−1,i−1+k),[i,i+k) 的结果不同的 i i i 的个数即可。
显然,排序 [ i − 1 , i − 1 + k ) , [ i , i + k ) [i-1,i-1+k),[i,i+k) [i−1,i−1+k),[i,i+k) 的结果不同当且仅当 P i − 1 P_{i-1} Pi−1 是 [ i − 1 , i + k ) [i-1,i+k) [i−1,i+k) 中的最小值, P i + k − 1 P_{i+k-1} Pi+k−1 是 [ i − 1 , i + k ) [i-1,i+k) [i−1,i+k) 中的最大值,用 S T ST ST 表或是单调队列解决即可。
时间复杂度 O ( N ) O(N) O(N) 或 O ( N L o g N ) O(NLogN) O(NLogN) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
namespace rmq {
const int MAXN = 2e5 + 5;
const int MAXLOG = 20;
int Max[MAXN][MAXLOG], Min[MAXN][MAXLOG], Log[MAXN];
int queryMax(int l, int r) {
int len = r - l + 1, tmp = Log[len];
return max(Max[l][tmp], Max[r - (1 << tmp) + 1][tmp]);
}
int queryMin(int l, int r) {
int len = r - l + 1, tmp = Log[len];
return min(Min[l][tmp], Min[r - (1 << tmp) + 1][tmp]);
}
void init(int *a, int n) {
for (int i = 1; i <= n; i++) {
Min[i][0] = a[i];
Max[i][0] = a[i];
Log[i] = Log[i - 1];
if ((1 << (Log[i] + 1)) <= i) Log[i]++;
}
for (int t = 1; t < MAXLOG; t++)
for (int i = 1, j = (1 << (t - 1)) + 1; j <= n; i++, j++) {
Max[i][t] = max(Max[i][t - 1], Max[j][t - 1]);
Min[i][t] = min(Min[i][t - 1], Min[j][t - 1]);
}
}
}
int n, k, a[MAXN];
bool flg[MAXN];
int main() {
read(n), read(k);
for (int i = 1; i <= n; i++)
read(a[i]);
rmq :: init(a, n);
int ans = 0, now = 0;
for (int i = 1; i <= k - 1; i++)
now += a[i] < a[i + 1];
for (int i = 1, j = k; j <= n; i++, j++) {
if (now == k - 1) {
ans = 1;
flg[i] = true;
}
now -= a[i] < a[i + 1];
now += a[j] < a[j + 1];
}
for (int i = 1, j = k; j <= n; i++, j++) {
if (flg[i]) continue;
if (i != 1 && a[i - 1] < rmq :: queryMin(i, j - 1) && a[j] > rmq :: queryMax(i, j - 1)) continue;
else ans++;
}
writeln(ans);
return 0;
}
Problem C. LCMs
考虑计算 ∑ i = 1 N ∑ j = 1 N L c m ( A i , A j ) sum_{i=1}^{N}sum_{j=1}^{N}Lcm(A_i,A_j) ∑i=1N∑j=1NLcm(Ai,Aj) ,最后减去 ∑ i = 1 N A i sum_{i=1}^{N}A_i ∑i=1NAi ,再除以 2 2 2 得到答案。
令
M
=
1
0
6
M=10^6
M=106 ,有
∑
i
=
1
N
∑
j
=
1
N
L
c
m
(
A
i
,
A
j
)
sum_{i=1}^{N}sum_{j=1}^{N}Lcm(A_i,A_j)
i=1∑Nj=1∑NLcm(Ai,Aj)
=
∑
i
=
1
N
∑
j
=
1
N
A
i
×
A
j
g
c
d
(
A
i
,
A
j
)
=sum_{i=1}^{N}sum_{j=1}^{N}frac{A_itimes A_j}{gcd(A_i,A_j)}
=i=1∑Nj=1∑Ngcd(Ai,Aj)Ai×Aj
=
∑
g
=
1
M
1
g
∑
i
=
1
N
∑
j
=
1
N
[
g
c
d
(
A
i
,
A
j
)
=
g
]
A
i
×
A
j
=sum_{g=1}^{M}frac{1}{g}sum_{i=1}^{N}sum_{j=1}^{N}[gcd(A_i,A_j)=g]A_itimes A_j
=g=1∑Mg1i=1∑Nj=1∑N[gcd(Ai,Aj)=g]Ai×Aj
=
∑
g
=
1
M
1
g
∑
g
∣
A
i
∑
g
∣
A
j
A
i
×
A
j
∑
g
d
∣
A
i
,
g
d
∣
A
j
μ
(
d
)
=sum_{g=1}^{M}frac{1}{g}sum_{gmid A_i}sum_{gmid A_j}A_itimes A_jsum_{gdmid A_i,gdmid A_j}mu(d)
=g=1∑Mg1g∣Ai∑g∣Aj∑Ai×Ajgd∣Ai,gd∣Aj∑μ(d)
=
∑
g
=
1
M
1
g
∑
d
=
1
M
g
μ
(
d
)
∑
g
d
∣
A
i
∑
g
d
∣
A
j
A
i
×
A
j
=sum_{g=1}^{M}frac{1}{g}sum_{d=1}^{frac{M}{g}}mu(d)sum_{gdmid A_i}sum_{gdmid A_j}A_itimes A_j
=g=1∑Mg1d=1∑gMμ(d)gd∣Ai∑gd∣Aj∑Ai×Aj
在上式中枚举
g
d
gd
gd 即可,需要计算
μ
mu
μ 和
1
i
d
frac{1}{id}
id1 卷积后的结果,以及输入中是
i
i
i 的倍数的数之和
v
a
l
u
e
i
value_i
valuei ,然后有
∑
i
=
1
N
∑
j
=
1
N
L
c
m
(
A
i
,
A
j
)
=
∑
g
d
=
1
M
(
1
i
d
∗
μ
)
(
g
d
)
×
v
a
l
u
e
g
d
2
sum_{i=1}^{N}sum_{j=1}^{N}Lcm(A_i,A_j)=sum_{gd=1}^{M}(frac{1}{id}*mu)(gd)times value_{gd}^2
i=1∑Nj=1∑NLcm(Ai,Aj)=gd=1∑M(id1∗μ)(gd)×valuegd2
时间复杂度 O ( N + M L o g M ) O(N+MLogM) O(N+MLogM) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
const int P = 998244353;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int tot, prime[MAXN], f[MAXN];
int miu[MAXN], inv[MAXN], func[MAXN];
void update(int &x, int y) {
x += y;
if (x >= P) x -= P;
}
int power(int x, int y) {
if (y == 0) return 1;
int tmp = power(x, y / 2);
if (y % 2 == 0) return 1ll * tmp * tmp % P;
else return 1ll * tmp * tmp % P * x % P;
}
void sieve(int n) {
miu[1] = 1;
for (int i = 2; i <= n; i++) {
if (f[i] == 0) {
prime[++tot] = f[i] = i;
miu[i] = P - 1;
}
for (int j = 1; j <= tot && prime[j] <= f[i]; j++) {
int tmp = prime[j] * i;
if (tmp > n) break;
f[tmp] = prime[j];
if (prime[j] == f[i]) miu[tmp] = 0;
else miu[tmp] = (P - miu[i]) % P;
}
}
for (int i = 1; i <= n; i++) {
inv[i] = power(i, P - 2);
for (int j = 1; i * j <= n; j++)
update(func[i * j], 1ll * inv[i] * miu[j] % P);
}
}
int a[MAXN], cnt[MAXN], value[MAXN];
int main() {
int n; read(n);
int m = 1e6; sieve(m);
for (int i = 1; i <= n; i++)
read(a[i]), cnt[a[i]]++;
for (int i = 1; i <= m; i++) {
for (int j = i; j <= m; j += i)
update(value[i], 1ll * j * cnt[j] % P);
}
int ans = 0;
for (int i = 1; i <= m; i++)
update(ans, 1ll * value[i] * value[i] % P * func[i] % P);
for (int i = 1; i <= n; i++)
update(ans, P - a[i]);
writeln(1ll * ans * inv[2] % P);
return 0;
}
Problem D. Unique Path
首先特判 M = N − 1 M=N-1 M=N−1 的情况,此时图是一棵树,不允许出现 C i = 1 C_i=1 Ci=1 的限制。
考虑 C i = 0 C_i=0 Ci=0 的限制,若将这些限制的 A i , B i A_i,B_i Ai,Bi 看做边,将会得到若干个连通块,不难证明,在原图中,这些连通块的导出子图均为树,不妨先将这些树连出来。
令剩余边数为 M ′ M' M′ ,连通块数为 C n t Cnt Cnt ,由于 M ≥ N Mgeq N M≥N , M ′ ≥ C n t M'geq Cnt M′≥Cnt 。
对于 C i = 1 C_i=1 Ci=1 的限制,若连接了两个同一棵树中的节点,则答案为 N o No No 。
否则,我们可以从每一棵树中取出一个点来连成一个环,以满足 C i = 1 C_i=1 Ci=1 的限制,但由于至多连成一个完全图,因此还需要满足 M ′ ≤ ( C n t 2 ) M'leqbinom{Cnt}{2} M′≤(2Cnt) 。
C n t = 2 Cnt=2 Cnt=2 的情况需要特判,此时不允许出现 C i = 1 C_i=1 Ci=1 的限制。
时间复杂度 O ( N + Q α ( N ) ) O(N+Qalpha(N)) O(N+Qα(N)) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int f[MAXN];
int F(int x) {
if (f[x] == x) return x;
else return f[x] = F(f[x]);
}
int x[MAXN], y[MAXN], type[MAXN];
int main() {
int n, q; ll m;
read(n), read(m), read(q);
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 1; i <= q; i++) {
read(x[i]), read(y[i]), read(type[i]);
x[i]++, y[i]++;
if (type[i] == 0) {
f[F(x[i])] = F(y[i]);
} else {
if (m == n - 1) {
puts("No");
return 0;
}
}
}
for (int i = 1; i <= q; i++)
if (type[i] && F(x[i]) == F(y[i])) {
puts("No");
return 0;
}
int cnt = 0;
for (int i = 1; i <= n; i++)
cnt += F(i) == i;
if (cnt <= 2) {
for (int i = 1; i <= q; i++)
if (type[i]) {
puts("No");
return 0;
}
}
ll ans = n - 1 - (cnt - 1);
ans += 1ll * cnt * (cnt - 1) / 2;
if (ans >= m) puts("Yes");
else puts("No");
return 0;
}
Problem E. Gachapon
考虑计算到达各个尚未完成的状态的概率之和,由期望的线性性,这也是答案。
令所有状态的指数型生成函数为 G ( x ) G(x) G(x) ,普通型生成函数为 g ( x ) g(x) g(x) ,已经完成的状态的指数型生成函数为 F ( x ) F(x) F(x) ,普通型生成函数为 f ( x ) f(x) f(x) ,那么我们要求的就是 g ( 1 ) − f ( 1 ) g(1)-f(1) g(1)−f(1) 。
考虑计算
H
(
x
)
=
G
(
x
)
−
F
(
x
)
H(x)=G(x)-F(x)
H(x)=G(x)−F(x) ,令
p
i
=
A
i
∑
A
i
p_i=frac{A_i}{sum A_i}
pi=∑AiAi ,有
H
(
x
)
=
e
x
−
∏
i
=
1
N
(
e
p
i
x
−
1
−
p
i
x
−
p
i
2
x
2
2
−
⋯
−
p
i
B
i
−
1
x
B
i
−
1
(
B
i
−
1
)
!
)
H(x)=e^x-prod_{i=1}^{N}(e^{p_ix}-1-p_ix-frac{p_i^2x^2}{2}-dots-frac{p_i^{B_i-1}x^{B_i-1}}{(B_i-1)!})
H(x)=ex−i=1∏N(epix−1−pix−2pi2x2−⋯−(Bi−1)!piBi−1xBi−1)
令
S
A
=
∑
A
i
,
y
=
e
1
S
A
x
SA=sum A_i,y=e^{frac{1}{SA}x}
SA=∑Ai,y=eSA1x ,那么
H
(
x
)
=
y
S
A
−
∏
i
=
1
N
(
y
A
i
−
1
−
p
i
x
−
p
i
2
x
2
2
−
⋯
−
p
i
B
i
−
1
x
B
i
−
1
(
B
i
−
1
)
!
)
H(x)=y^{SA}-prod_{i=1}^{N}(y^{A_i}-1-p_ix-frac{p_i^2x^2}{2}-dots-frac{p_i^{B_i-1}x^{B_i-1}}{(B_i-1)!})
H(x)=ySA−i=1∏N(yAi−1−pix−2pi2x2−⋯−(Bi−1)!piBi−1xBi−1)
暴力展开 H ( x ) H(x) H(x) 的计算式,对于各个 y i y^i yi ,展开关于 x x x 的多项式的时间复杂度均为 O ( ( ∑ B i ) 2 ) O((sum B_i)^2) O((∑Bi)2) ,因此展开的时间复杂度为 O ( ( ∑ A i ) × ( ∑ B i ) 2 ) O((sum A_i)times(sum B_i)^2) O((∑Ai)×(∑Bi)2) 。
接下来考虑如何将 H ( x ) H(x) H(x) 转为普通型生成函数求出 h ( 1 ) h(1) h(1) 。
对于形如
c
y
i
cy^i
cyi 的项,其对答案的贡献显然为
c
1
−
i
S
A
frac{c}{1-frac{i}{SA}}
1−SAic
考虑形如
c
y
i
x
j
cy^ix^j
cyixj 的项,其对答案的贡献应当为
c
∑
k
=
0
∞
(
i
S
A
)
k
×
(
k
+
1
)
×
(
k
+
2
)
×
⋯
×
(
k
+
j
)
csum_{k=0}^{infty}(frac{i}{SA})^ktimes(k+1)times(k+2)timesdotstimes(k+j)
ck=0∑∞(SAi)k×(k+1)×(k+2)×⋯×(k+j)
考虑对于
0
<
p
<
1
,
i
∈
N
0<p<1,iinmathbb{N}
0<p<1,i∈N ,计算
S
=
∑
k
=
0
∞
p
k
×
k
i
S=sum_{k=0}^{infty}p^ktimes k^i
S=k=0∑∞pk×ki
等式两侧同时乘以
p
p
p ,则有
p
S
=
∑
k
=
0
∞
p
k
+
1
×
k
i
pS=sum_{k=0}^{infty}p^{k+1}times k^i
pS=k=0∑∞pk+1×ki
那么
(
1
−
p
)
S
=
[
i
=
0
]
+
∑
k
=
0
∞
p
k
+
1
×
(
(
k
+
1
)
i
−
k
i
)
(1-p)S=[i=0]+sum_{k=0}^{infty}p^{k+1}times ((k+1)^i-k^i)
(1−p)S=[i=0]+k=0∑∞pk+1×((k+1)i−ki)
将 ( k + 1 ) i (k+1)^i (k+1)i 用二项式定理展开,即可将问题递归至更小的规模。
本部分时间复杂度也为 O ( ( ∑ A i ) × ( ∑ B i ) 2 ) O((sum A_i)times(sum B_i)^2) O((∑Ai)×(∑Bi)2) 。
总时间复杂度 O ( ( ∑ A i ) × ( ∑ B i ) 2 ) O((sum A_i)times(sum B_i)^2) O((∑Ai)×(∑Bi)2) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 405;
const int P = 998244353;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int n, sa, sb, a[MAXN], b[MAXN];
int f[MAXN][MAXN], g[MAXN], coef[MAXN][MAXN];
int fac[MAXN], inv[MAXN], binom[MAXN][MAXN];
int power(int x, int y) {
if (y == 0) return 1;
int tmp = power(x, y / 2);
if (y % 2 == 0) return 1ll * tmp * tmp % P;
else return 1ll * tmp * tmp % P * x % P;
}
void update(int &x, int y) {
x += y;
if (x >= P) x -= P;
}
int main() {
read(n), sa = 0, f[0][0] = 1;
for (int i = 1; i <= n; i++) {
read(a[i]), read(b[i]);
sa += a[i], sb += b[i];
}
fac[0] = inv[0] = binom[0][0] = 1;
for (int i = 1; i <= max(sa, sb); i++) {
fac[i] = 1ll * fac[i - 1] * i % P;
inv[i] = power(fac[i], P - 2);
binom[i][0] = 1;
for (int j = 1; j <= i; j++) {
binom[i][j] = (binom[i - 1][j - 1] + binom[i - 1][j]) % P;
}
}
for (int x = 1, s = 0; x <= n; s += b[x++]) {
memset(g, 0, sizeof(g));
int p = 1ll * a[x] * power(sa, P - 2) % P;
for (int i = 0, now = 1; i <= b[x] - 1; i++, now = 1ll * now * p % P)
g[i] = (P - 1ll * now * inv[i] % P) % P;
for (int i = sa; i >= 0; i--) {
static int tmp[MAXN];
memset(tmp, 0, sizeof(tmp));
for (int j = 0; j <= b[x]; j++)
for (int k = 0; k <= s; k++) {
update(tmp[j + k], 1ll * f[i][k] * g[j] % P);
}
memcpy(f[i], tmp, sizeof(tmp));
if (i >= a[x]) {
for (int j = 0; j <= s; j++)
update(f[i][j], f[i - a[x]][j]);
}
}
}
assert(f[sa][0] == 1);
int ans = 0;
for (int i = 0; i <= sb; i++)
update(ans, 1ll * f[0][i] * fac[i] % P);
coef[0][0] = 1;
for (int i = 1; i <= sb; i++)
for (int j = i; j >= 0; j--) {
coef[i][j] = 1ll * coef[i - 1][j] * i % P;
if (j != 0) update(coef[i][j], coef[i - 1][j - 1]);
}
for (int i = 1; i <= sa - 1; i++) {
static int res[MAXN];
int p = 1ll * i * power(sa, P - 2) % P;
memset(res, 0, sizeof(res)), res[0] = power((1 - p + P) % P, P - 2);
for (int j = 1; j <= sb; j++) {
int tmp = 0;
for (int k = 0; k <= j - 1; k++)
update(tmp, 1ll * binom[j][k] * res[k] % P);
res[j] = 1ll * tmp * p % P * res[0] % P;
}
for (int j = 0; j <= sb; j++) {
int tmp = 0;
for (int k = 0; k <= j; k++)
update(tmp, 1ll * res[k] * coef[j][k] % P);
update(ans, 1ll * tmp * f[i][j] % P);
}
}
writeln((P - ans) % P);
return 0;
}
Problem F. Two Permutations
将输入的排列 P , Q P,Q P,Q 看做两个置换,则其各个环或是整体被改为连向自身,或是不作修改。
注意到时间限制对于 1 0 5 10^5 105 的数据规模来说异常地大,考虑用最小割解题。
对于一个位置
i
i
i ,有如下几种情况:
(
1
)
(1)
(1) 、
P
i
=
Q
i
=
i
P_i=Q_i=i
Pi=Qi=i :此时无论是否改变都不会对答案造成影响。
(
2
)
(2)
(2) 、
P
i
=
Q
i
≠
i
P_i=Q_ine i
Pi=Qi=i :此时只改变
P
,
Q
P,Q
P,Q 中的一个可以使答案
+
1
+1
+1 。
(
3
)
(3)
(3) 、
P
i
=
i
≠
Q
i
P_i=ine Q_i
Pi=i=Qi :此时改变
Q
Q
Q 会使得答案
−
1
-1
−1 。
(
4
)
(4)
(4) 、
Q
i
=
i
≠
P
i
Q_i=ine P_i
Qi=i=Pi :此时改变
P
P
P 会使得答案
−
1
-1
−1 。
(
5
)
(5)
(5) 、
,
,
P
i
,
Q
i
,
i
,,P_i,Q_i,i
,,Pi,Qi,i 互不相同:同时改变
P
,
Q
P,Q
P,Q 会使得答案
−
1
-1
−1 。
由于要使用最小割解题,我们不希望出现增益的条件,考虑对
(
2
)
(2)
(2) 稍作修改。
(
2
)
(2)
(2) 、
P
i
=
Q
i
≠
i
P_i=Q_ine i
Pi=Qi=i :此时不改变
P
,
Q
P,Q
P,Q ,或同时改变
P
,
Q
P,Q
P,Q 会使得答案
−
1
-1
−1 。
对于 P P P 中的点,令将其划分在 S S S 集表示改变,划分在 T T T 集表示不改变;对于 Q Q Q 中的点,令将其划分在 T T T 集表示改变,划分在 S S S 集表示不改变。
那么对于上面的情况,我们分别可以按照如下方式连边。
(
2
)
(2)
(2) 、
P
↔
Q
Pleftrightarrow Q
P↔Q
(
3
)
(3)
(3) 、
S
→
Q
Srightarrow Q
S→Q
(
4
)
(4)
(4) 、
P
→
T
Prightarrow T
P→T
(
5
)
(5)
(5) 、
P
→
Q
Prightarrow Q
P→Q
时间复杂度 O ( D i n i c ( N , N ) ) O(Dinic(N,N)) O(Dinic(N,N)) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int INF = 2e9;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
namespace NetworkFlow {
const int INF = 2e9;
const int MAXP = 5e5 + 5;
struct edge {
int dest, flow;
unsigned pos;
};
vector <edge> a[MAXP];
int tot, s, t, dist[MAXP];
unsigned curr[MAXP];
void addedge(int x, int y, int z) {
a[x].push_back((edge) {y, z, a[y].size()});
a[y].push_back((edge) {x, 0, a[x].size() - 1});
}
int dinic(int pos, int limit) {
if (pos == t) return limit;
int used = 0, tmp;
for (unsigned &i = curr[pos]; i < a[pos].size(); i++)
if (a[pos][i].flow != 0 && dist[pos] + 1 == dist[a[pos][i].dest] && (tmp = dinic(a[pos][i].dest, min(limit - used, a[pos][i].flow)))) {
used += tmp;
a[pos][i].flow -= tmp;
a[a[pos][i].dest][a[pos][i].pos].flow += tmp;
if (used == limit) return used;
}
return used;
}
bool bfs() {
static int q[MAXP];
int l = 0, r = 0;
memset(dist, 0, sizeof(dist));
dist[s] = 1, q[0] = s;
while (l <= r) {
int tmp = q[l];
for (unsigned i = 0; i < a[tmp].size(); i++)
if (dist[a[tmp][i].dest] == 0 && a[tmp][i].flow != 0) {
q[++r] = a[tmp][i].dest;
dist[q[r]] = dist[tmp] + 1;
}
l++;
}
return dist[t] != 0;
}
int flow() {
int ans = 0;
while (bfs()) {
memset(curr, 0, sizeof(curr));
ans += dinic(s, INF);
}
return ans;
}
}
int n, a[MAXN], b[MAXN];
int va[MAXN], vb[MAXN];
int main() {
int n; read(n);
for (int i = 1; i <= n; i++)
read(a[i]), a[i]++;
for (int i = 1; i <= n; i++)
read(b[i]), b[i]++;
for (int i = 1; i <= n; i++) {
if (va[i]) continue;
int pos = i;
while (va[pos] == 0) {
va[pos] = i;
pos = a[pos];
}
}
for (int i = 1; i <= n; i++) {
if (vb[i]) continue;
int pos = i;
while (vb[pos] == 0) {
vb[pos] = i + n;
pos = b[pos];
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans += a[i] != b[i];
int s = NetworkFlow :: s = 2 * n + 1;
int t = NetworkFlow :: t = 2 * n + 2;
for (int i = 1; i <= n; i++) {
if (a[i] == b[i]) {
if (a[i] == i) continue; ans += 1;
NetworkFlow :: addedge(vb[i], va[i], 1);
NetworkFlow :: addedge(va[i], vb[i], 1);
} else {
if (a[i] == i) NetworkFlow :: addedge(s, vb[i], 1);
else if (b[i] == i) NetworkFlow :: addedge(va[i], t, 1);
else NetworkFlow :: addedge(va[i], vb[i], 1);
}
}
ans -= NetworkFlow :: flow();
writeln(ans);
return 0;
}
最后
以上就是阔达信封为你收集整理的【AtCoder】AtCoder Grand Contest 038比赛链接官方题解Problem A. 01 MatrixProblem B. Sorting a SegmentProblem C. LCMsProblem D. Unique PathProblem E. GachaponProblem F. Two Permutations的全部内容,希望文章能够帮你解决【AtCoder】AtCoder Grand Contest 038比赛链接官方题解Problem A. 01 MatrixProblem B. Sorting a SegmentProblem C. LCMsProblem D. Unique PathProblem E. GachaponProblem F. Two Permutations所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复