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.

*/
posted @ 2025-01-01 20:53  PM_pro  阅读(7)  评论(0)    收藏  举报