HDU - 5628:Clarke and math (组合数&线性筛||迪利克雷卷积)

Posted hua-dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 5628:Clarke and math (组合数&线性筛||迪利克雷卷积)相关的知识,希望对你有一定的参考价值。

技术分享图片

题意:略。

思路:网上是用卷积或者做的,不太会。 因为上一题莫比乌斯有个类似的部分,所以想到了每个素因子单独考虑。

我们用C(x^p)表示p次减少分布在K次减少里的方案数,由隔板法可知,C(x^p)=C(K+p-1,K-1);  而且满足C(x)有积性,即gcd(x,y)==1时,有C(x*y)=C(x)*C(y);

所以C数组可以线性筛。 把筛素数的线性筛,稍微改一下即可,low[i]代表的是i的最小素数因子x的p次方,即x^p|i,p最大,num[i]代表的是幂次p。

那么g(x)=Σ f(a)*C(x/a); g数组也可以线性筛。这里相当于手动卷积。

所以C和g函数分别线性筛即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=100010;
const int Mod=1e9+7;
int rev[maxn],f[maxn],ans[maxn],jc[maxn],fz[maxn],p[maxn];
int vis[maxn],low[maxn],num[maxn],C[maxn],cnt,N,K;
int qpow(int a,int x){
    int res=1; while(x){
        if(x&1) res=(ll)res*a%Mod;
        a=(ll)a*a%Mod; x>>=1;
    } return res;
}
void getC()
{
    cnt=0; rep(i,1,maxn) low[i]=num[i]=0;
    for(int i=2;i<maxn;i++){
        if(!vis[i]) p[++cnt]=i,low[i]=i,num[i]=1;
        for(int j=1;j<=cnt&&i*p[j]<maxn;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                low[i*p[j]]=low[i]*p[j];
                num[i*p[j]]=num[i]+1;
                break;
            }
            low[i*p[j]]=p[j];
            num[i*p[j]]=1;
        }
    }
}
int main()
{
    jc[0]=1;rep(i,1,maxn-1) jc[i]=(ll)jc[i-1]*i%Mod;
    rev[maxn-1]=qpow(jc[maxn-1],Mod-2);
    for(int i=maxn-2;i>=0;i--) rev[i]=(ll)rev[i+1]*(i+1)%Mod;
    getC();
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&K);
        fz[0]=1; rep(i,1,N) fz[i]=(ll)fz[i-1]*(i+K-1)%Mod,ans[i]=0;
        rep(i,1,N) scanf("%d",&f[i]);
        C[1]=1;
        rep(i,2,N) C[i]=(ll)C[i/low[i]]*rev[num[i]]%Mod*fz[num[i]]%Mod;
        for(int i=1;i<=N;i++){
         for(int j=i;j<=N;j+=i)
            (ans[j]+=(ll)f[i]*C[j/i]%Mod)%=Mod;
        }
        rep(i,1,N-1) printf("%d ",ans[i]);
        printf("%d
",ans[N]);
    }
    return 0;
}

 到此,引申一下有个题,给定N<1e7,K<1e9,求1^K+2^K+3^+...N^K。

这里由于K过大,显然不能用拉格朗日插值法。 我们用线性筛来做,如果i是素数,我们就快速幂求f[i]=i^K,否则就用之前的结果就好了,即f[i]=f[low[i]]^f[i/low[i]];

由于素数的个数大约=N/lgN; 而快速幂的复杂度是lgK。所以整个算法差不多是线性的。

 

以上是关于HDU - 5628:Clarke and math (组合数&线性筛||迪利克雷卷积)的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 5628:Clarke and math (组合数&线性筛||迪利克雷卷积)

hdu 5625 Clarke and chemistry

HDU 5627Clarke and MST

hdu 5626 Clarke and points

HDU 5464 Clarke and problem 动态规划

HDU 5465 Clarke and puzzle Nim游戏+二维树状数组