666
容易转化成求所有任易选几个数的情况的最大公因数和。
此时,有 \(m\le 10^5\)。
于是对于值域进行计算:
对于每个数 \(i\),我们需要找到最大公因数为 \(i\) 的这样几个数有多少组。如果直接暴力枚举,那么比直接不这样做还要慢。于是考虑一种快捷的方法计算,我们知道,如果一些数它们的最大公因数为 \(i\),\(i\) 就一定是它们的因数,所以那些数就一定由 \(i\) 的倍数组成。那是否是由 \(i\) 倍数的所有不同的选择方法组成的,不是。因为如果有一组数,它们全部是 \(i\) 的倍数,也有可能全部是 \(bi\) 的倍数。所以我们需要减去它的倍数的组数,到时候再减去就行了。在这个递归的运算过程中,必须要有一组是不会被 \(bi\) 影响的,正好所有数小于 \(m\),所以当 \(2i > m\) 时,此时算出来的 \(i\) 的组数是正确的,作为了递归边界。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define upp(a,x,y) for(int a=x;a<=y;a++)
#define dww(a,x,y) for(int a=x;a>=y;a--)
#define puts(a) cout<<a<<endl
#define pb(x) push_back(x)
using namespace std;
const int N=1e5+10,X=998244353;
vector<int> fac[N];
int n,a[N],sum[N],last[N],m,ans;
int qmi(int a,int b) {
int res=1;
while(b) {
if(b&1) res=(res*a)%X;
a=(a*a)%X;
b>>=1;
}
return res;
}
signed main() {
freopen("bead.in","r",stdin);
freopen("bead.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
upp(i,1,n) cin>>a[i];
upp(i,1,n) {
int tmp=a[i];
upp(j,1,tmp/j) {
if(tmp%j==0) {
if(tmp/j!=j) sum[tmp/j]++;
sum[j]++;
}
}
}
upp(i,1,m) last[i]=(qmi(2,sum[i])-1+X)%X;
dww(i,m,1) {
for(int j=2*i;j<=m;j+=i) last[i]=((last[i]-last[j])%X+X)%X;
(ans+=last[i]%X*i%X)%=X;
}
cout<<ans<<endl;
return 0;
}
/*
100 pts
Good luck.
*/