I题 小朋友你是否有很多问号

这个题我的基本思路就是对于每个数进行质因数分解,假如这个数分解成了p1*p2*...*px(这里忽略次方,因为没有意义),那么n个数中与这个数不互质的数则可以通过容斥原理计算出来,即为sum=num[p1]+num[p2]+...num[p1*p2*...*px],num[i]即为这n个数中能被i整除的数的个数,这个遵循奇加偶减即可,然后就知道了这n个数中与其互质的数为n-sum个,这样这个数对于答案的贡献就是a[i]*C(n-sum,m),(C(n,m)为高中组合数学),然后对于每个数字都当作m元公倍数计算一遍即可。
因为ai最大为100000,而2*3*5*7*9*11*13*15>100000,所以每个数最多分解成6个不同的质数,因此每个数分解出来之后最多有2^6(=64)个组合,(即p1*p2*p3可以组合成p1,p2,p1*p2,p1*p3,p2*p3,p1*p2*p3),这样每个组合都可以使得对应的num[]加1,列如p1*p3可以使得num[p1*p3]加1,这样我们就可以用64*n的复杂度计算出num数组,而且可以保证即使最大的p1*p2*...*px也不会超过100000(这个显而易见),然后再用64*n的复杂度计算出每个数对应的sum,进而得到答案。建议进行组合时用状压,这样比较方便好写。
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=101000;
const long long MOD=998244353;
vector<int>v[MAX_N];
int prime[1010],tot=0;
bool vis[1010];
void init(int x){//求质数
	int i,j;
	for(i=2;i<=x;i++){
		if(vis[i])
		continue;
		prime[++tot]=i;
		for(j=i+i;j<=x;j+=i)
		vis[j]=true;
	}
}
int p[MAX_N][7],cnt;
int tt[MAX_N];
int num[MAX_N];
long long F[MAX_N];
long long b[MAX_N];
long long pow_mod(long long a,long long n,long long m){
    long long ans=1;
    while(n){
        if(n&1){
            ans=(ans*a)%m;
        }
        a=(a*a)%m;
        n>>=1;
    }
    return ans;
}
long long C(int n,int m){//求组合数,提前预处理出阶乘数组F
	return F[n]*pow_mod(F[m]*F[n-m]%MOD,MOD-2,MOD)%MOD;
}
int main(void){
	int n,m,i,j,k,x;
	init(1000);
	scanf("%d%d",&n,&m);
	F[0]=1;
	for(i=1;i<=n;i++)
	F[i]=i*F[i-1]%MOD;
	for(i=1;i<=n;i++){
		scanf("%d",&x);
		b[i]=x;
		cnt=0;
		for(j=1;j<=tot;j++){
			if(x==1)
			break;
			if(x%prime[j]==0){
				while(x%prime[j]==0)
				x/=prime[j];
				p[i][cnt++]=prime[j];
			}
		}
		if(x!=1)
		p[i][cnt++]=x;
		for(j=0;j<(1<<cnt);j++){//用每个数分解的质数进行组合计算出num数组
			int s=1;
			for(k=0;k<cnt;k++){
				if(j&(1<<k)){
					s*=p[i][k];
				}
			}
			num[s]++;
		}
		tt[i]=cnt;
	}
	long long ans=0;
	for(i=1;i<=n;i++){
		cnt=tt[i];
		int res=0;
		for(j=1;j<(1<<cnt);j++){
			int s=1,sum=0;
			for(k=0;k<cnt;k++){
				if(j&(1<<k)){
					s*=p[i][k];
					sum++;
				}
			}//通过计算sum进行奇加偶减
			if(sum%2==1)
			res+=num[s];
			else
			res-=num[s];
		}
		res=n-res;
		if(res>=m)
		ans=(ans+b[i]*C(res,m)%MOD)%MOD;
	}
	printf("%lld\n",ans);
}


全部评论
还有种莫比乌斯函数做法,但是我不会😂
点赞 回复 分享
发布于 2020-05-03 23:46

相关推荐

点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务