ZOJ-3868-GCD Expectation(容斥)

6 篇文章 0 订阅


GCD Expectation

Time Limit: 4 Seconds      Memory Limit: 262144 KB

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.

Output

For each case, if the expectation is E, output a single integer denotes E · (2n - 1) modulo 998244353.

Sample Input
1
5 1
1 2 3 4 5
Sample Output
42



题目连接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5480



题意 ,给出序列a[1],a[2]...a[i],求子序列 [gcd(x1x2,…,xm)]k.   的期望乘  (2n - 1)  ,   显然子序列个数有 (2n - 1) 个,那么其实就是所有子序列gcd的k次方求和啦

数据范围不超1e6,那么可以直接枚举gcd就好啦,dp[i]表示gcd为i的组数,从高到低枚举gcd,计算出i的倍数出现了m次,那么就有2^m-1组为i倍数的子序列,

显然,dp[i]=2^m-1-dp[i*2]-dp[i*3]-....;



//#include<bits/stdc++.h>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 1e6+7;
const int MOD = 998244353;
long long a[MAXN],dp[MAXN];
long long quick_pow(long long a,long long n)
{
    long long ans=1;
    while(n)
    {
        if(n&1)ans*=a,ans%=MOD;
        a=a*a%MOD;
        n>>=1;
    }
    return ans;
}
int main()
{
    int T,n,k,temp;
    cin>>T;
    int cas=1;
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&k);
        int maxx=0,x;
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&x);
            a[x]++;
            maxx=max(maxx,x);
        }
        long long ans=0;
        for(int i=maxx; i>=1; --i)
        {
            int cnt=0,temp=0;
            for(int j=i; j<=maxx; j+=i)
            {
                cnt+=a[j];
                temp=(temp-dp[j]+MOD)%MOD;
            }
            dp[i]=((quick_pow(2,cnt)-1)%MOD+temp)%MOD;
            ans=(ans+dp[i]*quick_pow(i,k)%MOD)%MOD;
        }
        cout<<ans<<endl;
    }
    return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值