题目链接:https://codeforces.com/contest/1610/problem/D
贝祖定理:若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
n个整数间的裴蜀定理
设
a
1
,
a
2
,
a
3
,
.
.
.
,
a
n
a_1,a_2,a_3,...,a_n
a1,a2,a3,...,an为n个整数,
d
d
d是它们的最大公约数,那么存在整数
x
1
,
.
.
.
,
x
n
x_1,...,x_n
x1,...,xn使得
x
1
∗
a
1
+
x
2
∗
a
2
+
.
.
.
x
n
∗
a
n
=
d
x_1*a_1+x_2*a_2+...x_n*a_n=d
x1∗a1+x2∗a2+...xn∗an=d。
特别来说,如果
a
1
,
.
.
.
,
a
n
a_1,...,a_n
a1,...,an存在任意两个数是互质的(不必满足两两互质),那么存在整数
x
1
,
.
.
.
,
x
n
x_1,...,x_n
x1,...,xn使得
x
1
∗
a
1
+
x
2
∗
a
2
+
.
.
.
+
x
n
∗
a
n
=
1
x_1*a_1+x_2*a_2+...+x_n*a_n=1
x1∗a1+x2∗a2+...+xn∗an=1。证法类似两个数的情况。
借用一下某群友做好的图,下面第一点很容易想到,关键在于裴蜀定理的应用。
然后从题解的分析可以看到,当
g
c
d
gcd
gcd 为奇数时,上述条件必定满足,同时这种情况必定存在
y
i
y_i
yi为奇数,而存在
y
i
y_i
yi为奇数又表示公约数不可能为偶数,所以
g
c
d
gcd
gcd为奇数等价于存在
y
i
y_i
yi为奇数。
当
g
c
d
gcd
gcd 为偶数时,每个
y
i
y_i
yi 必然为偶数,取
l
>
0
l>0
l>0 的最大值,满足
2
l
2^l
2l 整除
g
c
d
gcd
gcd,若
2
l
2^l
2l 整除
y
i
/
2
y_i/2
yi/2,则
g
c
d
gcd
gcd 整除
(
y
i
+
1
)
y
i
/
2
(y_i+1)y_i/2
(yi+1)yi/2 ,否则不行,可以发现这时让
(
y
i
+
1
)
y
i
/
2
(y_i+1)y_i/2
(yi+1)yi/2 对
2
l
2^l
2l 取模会等于
2
l
−
1
2^{l-1}
2l−1,所以只有不足要求的
y
i
y_i
yi 个数为偶数时,
∑
(
y
i
+
1
)
y
i
/
2
\sum{(y_i+1)y_i/2}
∑(yi+1)yi/2 才被
2
l
2^l
2l 整除,所以也会被
g
c
d
gcd
gcd整除。
推导过程请看:
所以若存在yi为奇数的情况,无论如何都满足条件。只要存在奇数的情况都合法,所以问题是只要考虑全为偶数中合法情况数目即可。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
const ll MOD = 1e9 + 7;
int n, a[N], cnt[30], to[N];
int main(void) {
// freopen("in.txt", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
int x = 0;
while (a[i] % 2 == 0) {
a[i] >>= 1;
x++;
}
cnt[x]++;
}
to[0] = 1;
for (int i = 1; i <= N; i++)
to[i] = 2 * to[i - 1] % MOD;
// n-cnt[0]是偶数的个数,这里是计算出存在奇数的情况数
ll ans = (to[n] - to[n - cnt[0]] + MOD) % MOD;
// 接下来只考虑所有的yi都是偶数的情况
int y = n - cnt[0];
for (int l = 1; l < 30; l++) { // 当2^l整除gcd时,取的l的最大值
int x = y; // 当前可以参与选择的数的个数
y -= cnt[l]; // y 为满足 2^l 整除 yi/2的个数
if (x - y < 2) continue; // x - y = cnt[l] 小于 2 说明无这种情况可选
// 当cnt[l]中参与选择时,显然有一半是good序列,另一半不是good序列
// 因为C(cnt,0)+C(cnt, 2)+C(cnt, 4)+...是C(cnt,0)+C(cnt,1)+...+C(cnt,cnt)的一半,也就是2^cnt的一半
int delta = (to[x - 1] - to[y] + MOD) % MOD; // 但是还要减去cnt[l]中选择个数为0,即C(cnt,0)的可能数,不然会被重复计算
// 同时还有一种解释是,若cnt[l]中任一一个yi都不选,则最大的l满足2^l|gcd必定不是当前l
ans = (ans + delta) % MOD;
}
printf("%lld\n", ans);
return 0;
}
我觉得挺夸张的,这种推论题居然放在D题的位置,而且还有八九百个AC的,虽说来了许多1900以上的高手,但人和人的差距还是很大呀。