Codeforces 1097F
题意:给$n(n\leq 10^5)$个multiset
,然后进行如下操作:1 x v
:把第$x$个multiset
变成${v}$2 x y z
:把第$x$个multiset
变成$y∪z$3 x y z
:把第$x$个multiset
变成如下内容:$gcd(a,b)|a∈y,b∈z$4 x v
:查询$v$在第$x$个multiset
里出现的次数奇偶性
只关注奇偶性所以想到了bitset
……
然后刚开始我发现$gcd$操作可以反演/容斥去做……然后跪了
看别人代码发现只需要对询问进行反演即可。。
维护$f_x(i)$为第$x$个multiset
中$i$倍数的个数。
那么显然$y∪z$等价于$f_y(i)+f_z(i)$,$gcd(a,b)|a∈y,b∈z$等价于$f_y(i) \times f_z(i)$
然后根据位运算的技巧,$xor$是不进位的加法,$and$是不进位的乘法,所以上面操作
$f_y(i)+f_z(i) \Leftrightarrow f_y(i) xor f_z(i)$
$f_y(i) \times f_z(i) \Leftrightarrow f_y(i) and f_z(i)$
然后考虑怎么询问答案。设$g(i)$为$i$的个数。
我们已经维护了$f_x(i)$为第$x$个multiset
中$i$倍数的个数,那么根据反演:
$$
g(i)=\sum_{d=1}^{\lfloor \frac ni \rfloor} \mu(d)g(di)
$$
即可求出。对于反演式子中的乘法,可以预处理$bitset$的$\mu$,然后做$and$运算,加法即为最后得到的$bitset$中的$1$的个数。
知识点:
1、bitset
的空间计算方式为位数除以8
2、$xor$是不进位的加法,$and$是不进位的乘法
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<bitset>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
bitset<7001 > bs[100000 + 5], gg[7005], hh[7005];
// bs 即为上述 f, gg 为预处理的 mu, hh 为预处理的倍数
int n, q, mu[7005], pri[7005], vis[7005], tot;
void clean() {
ms(vis, 0), tot = 0;
}
int solve() {
clean();
mu[1] = 1;
for (int i = 2; i <= 7000; ++i) {
if (!vis[i]) vis[i] = 1, pri[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && 1ll * pri[j] * i <= 7000ll; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
mu[i * pri[j]] = 0;
break ;
} else mu[i * pri[j]] = mu[i] * mu[pri[j]];
}
}
for (int i = 1; i <= 7000; ++i)
for (int j = i; j <= 7000; j += i) hh[j][i] = 1, gg[i][j] = ((mu[j / i] == 0) ? 0 : 1); // 加减 1 等价
scanf("%d%d", &n, &q);
while (q--) {
int ty, x, y, z, v; scanf("%d", &ty);
if (ty == 1)
scanf("%d%d", &x, &v), bs[x] = hh[v];
if (ty == 2)
scanf("%d%d%d", &x, &y, &z), bs[x] = bs[y] ^ bs[z];
if (ty == 3)
scanf("%d%d%d", &x, &y, &z), bs[x] = bs[y] & bs[z];
if (ty == 4)
scanf("%d%d", &x, &v), printf("%d", (int)((bs[x] & gg[v]).count() & 1));
}
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}