题目链接:
题意:
已知一个n个元素的序列,任取一个非空子集({x1,x2,..,xm}),求 的期望。假设取任一子集的概率相同。最后答案乘以 。
思路:
定理:任意有n个元素的集合,其非空子集个数为 。
因为每种子集概率相同,即都为 ,最后答案 * ,相当于求任意非空子集 的和。
用 tot[i] 表示 gcd 为 i 的非空子集个数。
我们知道,一个数与它倍数的 gcd 就等于它本身,所以只要知道 i 的倍数的个数 p ,其总共可以有 种组合方式。但注意,其 gcd 不一定都等于 i ,因为这些组合中可能有不包含 i 这个数的情况,所以我们要把这些情况减掉,设剩下还有 x 种情况,那么最后答案 ans 就可以 += 。
而需要减掉的情况的个数等于gcd 为其倍数的非空子集个数,即 。
从Max -> 1计算tot[i]即可。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
const ll mod = 998244353;
ll n, k;
ll num[MAX];
ll tot[MAX];
ll multiply(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)
{
ans = ((ans%mod)*(a%mod)) % mod;
b--;
}
b /= 2;
a = ((a%mod)*(a%mod)) % mod;
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(num, 0, sizeof(num));
memset(tot, 0, sizeof(tot));
scanf("%lld%lld", &n, &k);
ll inf = 0;
for (int i = 0; i < n; i++) {
ll x;
scanf("%lld", &x);
inf = max(inf, x);
num[x]++;
}
ll ans = 0;
for (int i = inf; i >= 1; i--) {
ll p = 0;
for (int j = i; j <= inf; j += i) {
p += num[j];
tot[i] = (tot[i] - tot[j] + mod) % mod;
}
tot[i] = (tot[i] + multiply(2, p) - 1 + mod) % mod;
ans = (ans + tot[i] * multiply(i, k) % mod) % mod;
}
printf("%lld\n", ans);
}
return 0;
}