CF1322C - Instant Noodles
题意
给一个 2 N 2N 2N个点的二分图,左右两遍各 N N N个点,现在给出右边每个点的权值 v i v_i vi,以及 M M M条连接左右两边的边。左边选取一个非空集合 S S S,与之有边相连的右边的点集为 N ( S ) N(S) N(S), N ( S ) N(S) N(S)中点权值和为 f ( S ) f(S) f(S),现在求所有可能的 f ( S ) f(S) f(S)的 g c d gcd gcd值
题解
记
g
c
d
=
g
c
d
(
a
,
b
)
gcd=gcd(a,b)
gcd=gcd(a,b),
a
∣
b
a|b
a∣b为
a
a
a整除
b
b
b
g
c
d
∣
a
,
g
c
d
∣
b
,
g
c
d
∣
(
a
+
b
)
gcd|a,gcd|b,gcd|(a+b)
gcd∣a,gcd∣b,gcd∣(a+b),且
g
c
d
(
a
,
b
,
a
+
b
)
≤
m
i
n
(
a
,
b
,
a
+
b
)
≤
a
,
b
≤
a
+
b
gcd(a,b,a+b)\leq min(a, b, a+b)\leq a,b\leq a+b
gcd(a,b,a+b)≤min(a,b,a+b)≤a,b≤a+b
=>
g
c
d
(
a
,
b
)
=
g
c
d
(
a
,
b
,
a
+
b
)
gcd(a,b)=gcd(a,b,a+b)
gcd(a,b)=gcd(a,b,a+b)
现在考虑集合
S
1
,
S
2
S_1,S_2
S1,S2
①
N
(
S
1
)
N(S_1)
N(S1)和
N
(
S
2
)
N(S_2)
N(S2)无交集
=>
f
(
S
1
+
S
2
)
=
f
(
S
1
)
+
f
(
S
2
)
f(S_1+S_2)=f(S_1)+f(S_2)
f(S1+S2)=f(S1)+f(S2)
=>
g
c
d
(
f
(
S
1
)
,
f
(
S
2
)
,
f
(
S
1
)
+
f
(
S
2
)
)
=
g
c
d
(
f
(
S
1
)
,
f
(
S
2
)
)
gcd(f(S_1),f(S_2),f(S_1)+f(S_2))=gcd(f(S_1),f(S_2))
gcd(f(S1),f(S2),f(S1)+f(S2))=gcd(f(S1),f(S2))
②
N
(
S
1
)
N(S_1)
N(S1)和
N
(
S
2
)
N(S_2)
N(S2)有交集
=>
N
(
S
1
)
∩
N
(
S
2
)
=
N
(
S
3
)
N(S_1)∩N(S_2)=N(S_3)
N(S1)∩N(S2)=N(S3)
=>
f
(
S
1
+
S
2
)
=
f
(
S
1
−
S
3
)
+
f
(
S
2
−
S
3
)
+
f
(
S
3
)
f(S_1+S_2)=f(S_1-S_3)+f(S_2-S_3)+f(S_3)
f(S1+S2)=f(S1−S3)+f(S2−S3)+f(S3)
所以其实所有
f
(
S
)
f(S)
f(S)都可以用各个不一样的
f
(
S
i
)
f(S_i)
f(Si)相加得到
即右边的点只会对应一个集合,那么我们从右边的点来确定左边的集合即可
最后答案就是
a
n
s
=
g
c
d
(
f
(
S
1
)
,
f
(
S
2
)
,
.
.
.
,
f
(
S
k
)
)
ans=gcd(f(S_1),f(S_2),...,f(S_k))
ans=gcd(f(S1),f(S2),...,f(Sk))
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 5e5 + 10;
int T, N, M;
ll val[MAX];
set<int> g[MAX];
map<set<int>, ll> mp;
//集合的映射,这里hash也能做
//这样最后mp里面的值就是所有的f(S[i])了
int main() {
scanf("%d", &T);
while (T--) {
mp.clear();
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i++) scanf("%lld", &val[i]), g[i].clear();
while (M--) {
int u, v; scanf("%d%d", &u, &v);
g[v].insert(u);//右边的点确定的集合, 用g[v]来表示
}
for (int v = 1; v <= N; v++)
if (!g[v].empty())
mp[g[v]] += val[v];//找对应的集合
ll ans = 0;//全是0那答案就是0
for (auto &i: mp) ans = ans ? __gcd(ans, i.second) : i.second;
printf("%lld\n", ans);
}
return 0;
}