[BZOJ4305] 数列的GCD
题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4305
Solution
设\(a_i\)表示\(d=i\)时的答案,恰好\(k\)个不同也就是恰好\(n-k\)个相同,设\(s=n-k\)。
设有\(c\)个题目给出来数是的\(i\)的倍数,则可以得到\(a_i\)的表达式:
\[ a_i=\binom{c}{s}\cdot (\lfloor\frac{m}{i}\rfloor-1)^{c-s}\cdot \lfloor\frac{m}{i}\rfloor^{n-c}-\sum_{j=2}^{m/i}a_{ij} \]
我们发现前面的部分算到了\(\gcd\)是\(i\)的倍数的情况,所以在后面减掉。
利用调和级数,复杂度为\(O(n\log n)\)。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 3e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
int a[maxn],t[maxn],n,m,k,b[maxn],fac[maxn],ifac[maxn],inv[maxn];
int qpow(int a,int x) {
int res=1;
for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
return res;
}
void prepare(int l) {
inv[0]=inv[1]=fac[0]=ifac[0]=1;
FOR(i,1,l) fac[i]=1ll*fac[i-1]*i%mod;
FOR(i,2,l) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
FOR(i,1,l) ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
}
int c(int x,int y) {return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
int main() {
read(n),read(m),read(k);for(int i=1,x;i<=n;i++) read(x),b[x]++;k=n-k;
prepare(max(m,n));
for(int i=1;i<=m;i++)
for(int j=i;j<=m;j+=i) t[i]+=b[j];
for(int i=m;i;i--) {
if(t[i]<k) continue;
a[i]=1ll*c(t[i],k)*qpow(m/i-1,t[i]-k)%mod*qpow(m/i,n-t[i])%mod;
for(int j=i<<1;j<=m;j+=i) a[i]=(a[i]-a[j])%mod;
}
for(int i=1;i<=m;i++) printf("%d ",(a[i]+mod)%mod);puts("");
return 0;
}