题目描述
给出一个长度为N的数列{a[n]},1<=a[i]<=M(1<=i<=N)。
现在问题是,对于1到M的每个整数d,有多少个不同的数列b[1], b[2], …, b[N],满足:
(1)1<=b[i]<=M(1<=i<=N);
(2)gcd(b[1], b[2], …, b[N])=d;
(3)恰好有K个位置i使得a[i]<>bi
注:gcd(x1,x2,…,xn)为x1, x2, …, xn的最大公约数。
输出答案对1,000,000,007取模的值。
瞎做
我设f[i]表示d=i的答案
用一个g[i]表示所有i|d的d的答案和。
然后莫比乌斯反演一波。
所以我们只需要算g。
可以通过预处理求出不是d的倍数有t个。
那么这个t个一定不和原来相同
剩下n-t个中要有k-t个和原来相同
就是一个组合数咯
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=300000+10,mo=1000000007;
int mu[maxn],cnt[maxn],b[maxn],pri[maxn],f[maxn],g[maxn],fac[maxn],inv[maxn],a[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,top;
int quicksortmi(int x,int y){
if (!y) return 1;
int t=quicksortmi(x,y/2);
t=(ll)t*t%mo;
if (y%2) t=(ll)t*x%mo;
return t;
}
int C(int n,int m){
if (n<m||n<0||m<0) return 0;
return (ll)fac[n]*inv[m]%mo*inv[n-m]%mo;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
fo(i,1,n){
scanf("%d",&a[i]);
b[a[i]]++;
}
fo(i,1,m)
fo(j,1,m/i)
cnt[i]+=b[i*j];
fac[0]=1;
fo(i,1,n) fac[i]=(ll)fac[i-1]*i%mo;
inv[n]=quicksortmi(fac[n],mo-2);
fd(i,n-1,0) inv[i]=(ll)inv[i+1]*(i+1)%mo;
top=0;
mu[1]=1;
fo(i,2,m){
if (!bz[i]){
pri[++top]=i;
mu[i]=-1;
}
fo(j,1,top){
if ((ll)i*pri[j]>m) break;
bz[i*pri[j]]=1;
if (i%pri[j]==0){
mu[i*pri[j]]=0;
break;
}
mu[i*pri[j]]=-mu[i];
}
}
fo(i,1,m){
t=n-cnt[i];
if (k<t) continue;
g[i]=(ll)C(n-t,k-t)*quicksortmi(m/i-1,k-t)%mo*quicksortmi(m/i,t)%mo;
}
fo(i,1,m){
fo(j,1,m/i)
f[i]=(f[i]+g[i*j]*mu[j])%mo;
(f[i]+=mo)%=mo;
printf("%d%c",f[i],i==m?'\n':' ');
}
}