[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=\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;
}

转载于:https://www.cnblogs.com/hbyer/p/11061104.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值