• HDU 5628 Clarke and math Dirichlet卷积+快速幂


    题意:bc round 72 中文题面

    分析(官方题解):

    如果学过Dirichlet卷积的话知道这玩意就是g(n)=(f*1^k)(n),

    由于有结合律,所以我们快速幂一下1^k就行了。

    当然,强行正面刚和式也是能搞的(反正我不会)。

    一次Dirichlet卷积复杂度是O(nlogn)的,所以总时间复杂度为O(nlognlogk).

    注:普及Dirichlet卷积概念,设f,g为两个数论函数,

    那么规定 (f∗g)=∑d|nf(d)g(n/d)为f,g的Dirichlet卷积

    Dirichlet卷积有以下性质,有交换律和结合律,对加法有分配律
    f∗(g∗h)=(f∗g)∗h
    f∗(g+h)=f∗g+f∗h
    f∗g=g∗f

    然后对于这个题解上所说的一次Dirichlet卷积是O(nlogn)这个我不是很懂

    但是看网上大神写的估计也差不多,感觉和埃氏筛的复杂度差不多甚至还要小应该是在O(nlognlogn)左右

    所以下面的代码的复杂度大概应该是O(nlog^2nlogk)

    然后顺带提一下,对于Dirichlet卷积来说,规定有一个幺元e的话

    即:f*e=f,

    这个幺元函数有一个性质e[1]=1,e[k]=0,k=1,2,3.....

    这个在快速幂的时候会用到

    然后上代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long LL;
    const int N=1e5+5;
    const LL mod=1e9+7;
    int n,k;
    LL f[N],s[N],ans[N],tmp[N];
    void solve()
    {
        while(k)
        {
            if(k&1)
            {
                for(int i=1; i<=n; ++i)tmp[i]=0;
                for(int i=1; i*i<=n; ++i)
                {
                    tmp[i*i]=(tmp[i*i]+ans[i]*s[i])%mod;
                    for(int j=i+1; j*i<=n; ++j)
                        tmp[i*j]+=(ans[i]*s[j]%mod+ans[j]*s[i]%mod)%mod,tmp[i*j]%=mod;
                }
                for(int i=1; i<=n; ++i)ans[i]=tmp[i];
            }
            for(int i=1; i<=n; ++i)tmp[i]=0;
            for(int i=1; i*i<=n; ++i)
            {
                tmp[i*i]=(tmp[i*i]+s[i]*s[i])%mod;
                for(int j=i+1; j*i<=n; ++j)
                    tmp[i*j]+=(s[i]*s[j]%mod+s[j]*s[i]%mod)%mod,tmp[i*j]%=mod;
            }
            for(int i=1;i<=n;++i)s[i]=tmp[i];
            k>>=1;
        }
        for(int i=1; i<=n; ++i)tmp[i]=0;
        for(int i=1; i*i<=n; ++i)
        {
            tmp[i*i]=(tmp[i*i]+f[i]*ans[i])%mod;
            for(int j=i+1; j*i<=n; ++j)
                tmp[i*j]+=(f[i]*ans[j]%mod+f[j]*ans[i]%mod)%mod,tmp[i*j]%=mod;
        }
        for(int i=1;i<=n;++i)ans[i]=tmp[i];
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&k);
            for(int i=1; i<=n; ++i)
                scanf("%I64d",&f[i]),s[i] = 1,ans[i] = 0;
            ans[1] = 1;
            solve();
            for(int i=1; i<n; ++i)
                printf("%I64d ",ans[i]);
            printf("%I64d
    ",ans[n]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    21.显式锁(Lock)的使用
    20.线程间通讯(wait、notify应用)
    18.等待唤醒机制(wait、notify)
    java实现枚举转换成list
    19.wait与sleep的区别
    SpringBoot整合Redis和SpringBoot(SpringCache)整合Redis
    MySQL基础
    Redis操作指令
    python 处理 JSON
    Redis安装CentOS
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5205684.html
Copyright © 2020-2023  润新知