题意:
给定n,k和n个数,要求出n个数所有非空子集的gcd^k的数学期望乘上(2^n-1)。
思路:
其实就是求所有非空子集的gcd^k的和。。。
由于a[i]不大,可以枚举gcd
设gcd=x, 我们需要求出gcd为x的子集有多少个,显然我们可以求出gcd为x,2x,3x,4x........的子集有多少个, 也就是能被x整出的数有y个的话,gcd为x的倍数的子集就有2 ^ y - 1个,求出gcd为x的倍数的子集个数后,可以减去gcd为2x,3x,4x...的子集的个数就是gcd为x的子集个数。
cnt[i]表示值为i个数有多少个
s[i]表示有多少个数能被i整除
mul[i]表示gcd为i的倍数的子集有多少个,减去mul[2i],mul[3i]。。。之后就是gcd为i个子集个数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1000020
#define M 10000
#define mod 998244353
#define LL long long
#define Pi acos(-1.0)
#define inf 0x3f3f3f3f
int n, a[N], k, mx;
int cnt[N], s[N];
LL mul[N];
LL qpow(LL x, int k) {
LL ret = 1;
while(k) {
if(k & 1) ret = ret * x % mod;
x = x * x % mod;
k >>= 1;
}
return ret;
}
int main() {
int cas;
scanf("%d", &cas);
while(cas--) {
scanf("%d%d", &n, &k);
mx = 1;
memset(cnt, 0, sizeof cnt);
memset(s, 0, sizeof s);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
mx = max(mx, a[i]);
cnt[a[i]]++;
}
for(int i = 1; i <= mx; ++i) {
for(int j = i; j <= mx; j += i) {
s[i] += cnt[j];
}
}
for(int i = 1; i <= mx; ++i) {
mul[i] = qpow(2, s[i]) - 1;
if(mul[i] < 0) mul[i] += mod;
}
for(int i = mx; i >= 1; --i) {
for(int j = i + i; j <= mx; j += i) {
mul[i] = ((mul[i] - mul[j]) % mod + mod) % mod;
}
}
LL ans = 0;
for(int i = 1; i <= mx; ++i) {
LL tmp = mul[i] * qpow(i, k) % mod;
ans = (ans + tmp) % mod;
}
printf("%lld\n", ans);
}
return 0;
}