【51Nod1769】Clarke and math2(数论,组合数学)

【51Nod1769】Clarke and math2(数论,组合数学)

题面

51Nod

题解

考虑枚举一个\(i_k\),枚举一个\(i\),怎么计算\(i_k\)\(i\)的贡献。
\(\frac{i}{i_k}\)拆掉,维护一个长度为\(k\)的数组,表示\(\frac{i_{k-1}}{i_{k}}\),对于每一个质因子,假设其出现次数为\(a\),那么就是把\(a\)个元素放进\(k\)个盒子里,盒子可以空,这个的方案数是\({a+k-1\choose k-1}={a+k-1\choose a}\),不难发现\(a\)很小,所以可以直接\(O(a)\)暴力算。
于是我们提前对于每一个\(a\)算出方案数,然后提前把质因数分解好,就可以做到\(O(nlogn)\)了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 500500
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=(x*10ll+ch-48)%MOD,ch=getchar();
    return t?-x:x;
}
int n,K,C[25],f[MAX],g[MAX],x[MAX],v[MAX],inv[25];
int main()
{
    n=read();K=read();
    for(int i=1;i<=n;++i)f[i]=read();
    inv[0]=inv[1]=1;for(int i=2;i<=20;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    for(int i=1;i<=20;++i)inv[i]=1ll*inv[i-1]*inv[i]%MOD;
    for(int a=0;a<=20;++a)
    {
        int nw=(a+K-1)%MOD;C[a]=inv[a];
        for(int i=0;i<a;++i)C[a]=1ll*C[a]*(nw-i+MOD)%MOD;
    }
    for(int i=1;i<=n;++i)x[i]=i,v[i]=1;
    for(int i=2;i<=n;++i)
        if(x[i]!=1)
            for(int j=i;j<=n;j+=i)
            {
                int a=0;
                while(x[j]%i==0)++a,x[j]/=i;
                v[j]=1ll*v[j]*C[a]%MOD;
            }
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;j+=i)
            g[j]=(g[j]+1ll*f[i]*v[j/i])%MOD;
    for(int i=1;i<=n;++i)printf("%d ",g[i]);
    puts("");return 0;
}
posted @ 2019-07-05 16:53 小蒟蒻yyb 阅读(...) 评论(...) 编辑 收藏