GCD Expectation
Edward has a set of n integers {a1, a2,...,an}. He randomly picks a nonempty subset {x1, x2,…,xm} (each nonempty subset has equal probability to be picked), and would like to know the expectation of [gcd(x1, x2,…,xm)]k.
Note that gcd(x1, x2,…,xm) is the greatest common divisor of {x1, x2,…,xm}.
Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains two integers n, k (1 ≤ n, k ≤ 106). The second line contains n integers a1, a2,…,an (1 ≤ ai ≤ 106).
The sum of values max{ai} for all the test cases does not exceed 2000000.
OutputFor each case, if the expectation is E, output a single integer denotes E · (2n - 1) modulo 998244353.
Sample Input1 5 1 1 2 3 4 5Sample Output
42
题意:
给你n个数{a1,a2,a3……an},让我们这个集合的任意子集的最大公因数的k次方求和
思路:
我们可以把题目转换成求gcd等于i的非空集合有多少个,这样就可以直接计算了。
我们在输入的时候存下n个数中的最大的记为Max,因为这n个数的最大公因子一定不可能超过Max,并且记录下每个数的个数
gcd i从Max枚举到1
对于每个最大公因子i,我们要求出i的倍数的的数有多少,内层循环从i开始,到Max每次+i,成倍增加,因为我们已经记录下每个数的个数了,没有的就是零,这样循环过程直接加就可以得到i的倍数的个数
设n个数中是i的倍数的数有x个。
那么gcd等于i的个数就是总共的 (2^x-1)个(以i为倍数的所有集合)减去gcd等于j的个数,j是i的倍数(也就是最大公因数是i 的倍数的个数),这里相当于一个容斥定理的最简单的情况。
最后的gcd为i的个数dp[i]后,直接求dp[i]*q_pow(i,k)加到答案中取模即可
code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int maxn = 1e6+100;
int sum[maxn];//给定的每个数的个数
int a[maxn];//给定的数组
int dp[maxn];//dp[i]是以i这个数为最大公因数的数的个数
ll q_pow(ll a,ll b){
ll ans = 1;
while(b){
if(b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
int n,k,Max = 0;
scanf("%d%d",&n,&k);
for(int i = 0; i < n; i++){
scanf("%d",&a[i]);
Max = max(a[i],Max);
sum[a[i]]++;
}
ll ans = 0;
for(int i = Max; i >= 1; i--){
int cnt = 0;
for(int j = i; j <= Max; j += i){
cnt += sum[j];//记录i的倍数有多少个
dp[i] = (dp[i] - dp[j] + mod) % mod;
//计算以i为最大公因数的数有多少,总的i的倍数的集合减去
//以i的倍数为最大公因数的个数
}
dp[i] = ((dp[i] + q_pow(2,cnt) - 1) % mod + mod) % mod;
ans = (ans + dp[i] * q_pow(i,k)) % mod;//算gcd的k次方,并且有dp[i]个
}
printf("%lld\n",ans);
}
return 0;
}