原题解链接:https://ac.nowcoder.com/discuss/157310
由题面可知没有平方根,加上的最大质因子为,说明它的质因子种数只有种。 那么可映射成一个位的二进制数。 即
其中 为第大的素数, 为第位二进制位, 我们不妨设
则
那么对于来说,它的表示方法的种数有 其中 为数组中经过映射后等于i的个数, 为数组中经过映射后等于的个数,为数组中经过映射后等于的个数。
这里再用卷积加速即可。
#include <stdio.h>
#define rep(i, j, k) for(int i = (j); i <= (k); ++i)
typedef long long ll;
const int MOD = 1e9 + 7;
const int rev = (MOD + 1) / 2;
int p[105], a[3][(1 << 22)];
void FWT(int a[],int n){
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++){
int x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)%MOD,a[i+j+d]=(x-y+MOD)%MOD;
}
}
void UFWT(int a[], int n) {
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++){
int x=a[i+j],y=a[i+j+d];
a[i+j]=1ll*(x+y)*rev%MOD,a[i+j+d]=(1ll*(x-y+MOD)%MOD*rev%MOD)%MOD;
}
}
void solve(int a[],int b[],int n){
FWT(a,n);
FWT(b,n);
for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%MOD;
UFWT(a,n);
}
int main(){
int c = 0;
rep(i, 2, 71){
bool flag = true;
rep(j, 2, i - 1) if(i % j == 0) flag = false;
if(flag) p[c++] = i;
}
int n; scanf("%d", &n);
rep(k, 0, 2) rep(i, 1, n){
ll t; scanf("%lld", &t);
int x = 0; rep(j, 0, c-1) if(t % p[j] == 0) x |= (1 << j);
a[k][x]++;
// printf("t:%lld x:%d\n", t, x);
}
// rep(k, 0, 2) rep(j, 0, 1<<c) printf("%d%c", a[k][j], " \n"[j==(1<<c)]);
solve(a[0], a[1], (1 << c));
// rep(k, 0, 2) rep(j, 0, 1<<c) printf("%d%c", a[k][j], " \n"[j==(1<<c)]);
solve(a[0], a[2], (1 << c));
// rep(k, 0, 2) rep(j, 0, 1<<c) printf("%d%c", a[k][j], " \n"[j==(1<<c)]);
int ans = 0;
rep(i, 0, (1 << c) - 1){
int x = 1;
rep(j, 0, c - 1) if(i >> j & 1) x = (ll)x * p[j] % MOD;
// if(a[0][i]) printf("x:%d c:%d\n", x, a[0][i]);
ans = (ans + (ll)x * a[0][i] % MOD) % MOD;
}
printf("%d\n", ans);
return 0;
}