[BZOJ4305] 数列的GCD

[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=inom{c}{s}cdot (lfloorfrac{m}{i} floor-1)^{c-s}cdot lfloorfrac{m}{i} floor^{n-c}-sum_{j=2}^{m/i}a_{ij} ]

我们发现前面的部分算到了(gcd)(i)的倍数的情况,所以在后面减掉。

利用调和级数,复杂度为(O(nlog 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('
');}
 
#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;
}
原文地址:https://www.cnblogs.com/hbyer/p/11061104.html