zoukankan      html  css  js  c++  java
  • 51nod1847 奇怪的数学题

    Description

    http://www.51nod.com/Challenge/Problem.html#problemId=1847

    计算下式

    \[\sum_{i=1}^n\sum_{j=1}^n sgcd(i,j)^k\mod 2^{32} \]

    \(sgcd\) 函数表示第二大的 \(\texttt{common divisor}\),当 \(gcd(i,j)=1\)\(sgcd(i,j)=0\),例如 \(sgcd(3,5)=0,sgcd(15,10)=1\)

    \(n\le 10^9,k\le 50\)

    Solution

    写这题是为了复习模板

    \(f(x)\) 表示 \(x\) 的最大真因子,原式改写成

    \[\begin{aligned} \\&= \sum_{d=1}^n f(d)^k\sum_{i=1}^n\sum_{j=1}^n [gcd(i,j)=d] \\&=\sum_{d=1}^n f(d)^k (2\sum_{i=1}^{\lfloor \frac nd\rfloor}\varphi(i)-1) \end{aligned}\]

    后半部分是杜教筛模板,外层套整除分块即可得到,那么仍需求出 \(f^k(i)\) 函数前缀和

    函数本身并没有什么特别的积性,但是考察 \(\min25\) 筛法的第一个 \(\rm{DP}\) 的过程:依次枚举质因子并从每个 \(g(n,i-1)\) 中去掉 \(i\) 在这其中的贡献

    形式化的表达式写作

    \(g[n][i]=g[n][i-1]-(pri_i^k)\times(g[\lfloor\frac{n}{pri_i}]\rfloor[i-1]-g[pri_{i-1}][i-1])\)

    其中 g[n/pri[i]][i-1]-g[pri[i-1]][i-1] 的含义恰是将那些最大质因子为 pri[i] 的数字去掉最大质因子之后剩下的数字的 \(k\) 次幂值之和,那么可以贡献给 \(f^k(pri_i)\)

    另外由于要处理 \(sgcd(pri_i,pri_i)\) 的值,所以在 \(\min25\) 筛法的过程中需要计算范围内的质数数量,这相对 trivial

    \(\min25\) 筛的初始状态需要赋值 \(g(n,0)=\sum\limits_{i=1}^n i^k\),因为模数的原因不能使用依赖于逆元的 \(\rm Lagrange\) 插值

    一种可能的解决方法是出于指数很小使用第二类斯特林数,即

    \[\begin{aligned}\\& \sum_{i=1}^n i^k \\&=\sum_{i=1}^n\sum_{j=0}^k j!\begin{Bmatrix}k\\j\end{Bmatrix}\binom ij \\&=\sum_{j=0}^k j! \begin{Bmatrix}k\\j\end{Bmatrix}\sum_{i=1}^n \binom ij \\&=\sum_{j=0}^k j! \begin{Bmatrix}k\\j\end{Bmatrix}\binom {n+1}{j+1} \\&=\sum_{j=0}^k \begin{Bmatrix}k\\j\end{Bmatrix} \frac{(n+1)^{\underline{j+1}}}{j+1} \end{aligned}\]

    由于连续 \(j+1\) 个数中必然有一个 \(j+1\) 的倍数,所以找到之除掉后就没有除法操作了

    Code

    #define uint unsigned int
    const int N=2e6+10;
    int pri[N],cnt,fl[N];
    map<int,uint> mp;
    uint phi[N],Str[100][100],res[N],num[N],f[N],sum[N];
    int R[N],tot,n,k,bl,id1[N],id2[N];
    inline uint getphi(int n){
        if(n<=2e6) return phi[n];
        if(mp.count(n)) return mp[n];
        uint ans=(n&1)?(uint)(n+1)/2*n:(uint)n/2*(n+1);
        for(int l=2,r;l<=n;l=r+1){
            r=n/(n/l);
            ans-=(uint)(r-l+1)*getphi(n/l);
        }
        return mp[n]=ans;
    }
    inline int getid(int x){
        if(x<=bl) return id1[x];
        else return id2[n/x];
    }
    inline uint calc(int n){
        int pos=getid(n);
        return res[pos]+num[pos];
    }
    inline uint S(int n,int k){
        uint ans=0;
        rep(j,0,k){
            uint tmp=1,now=n+1;
            bool fl=0;
            rep(i,0,j){
                if(fl==0&&now%(j+1)==0) tmp*=now/(j+1),fl=1;
                else tmp*=now;
                --now;
            }
            ans+=tmp*Str[k][j];
        }
        return ans;
    }
    inline uint ksm(uint x,int y){
        uint res=1;
        for(;y;y>>=1,x=x*x) if(y&1) res*=x;
        return res;
    }
    signed main(){
        n=2e6; phi[1]=1;
        for(int i=2;i<=n;++i){
            if(!fl[i]) phi[i]=i-1,pri[++cnt]=i;
            for(int j=1;j<=cnt&&1ll*i*pri[j]<=n;++j){
                fl[i*pri[j]]=1;
                if(i%pri[j]==0){
                    phi[i*pri[j]]=phi[i]*pri[j];
                    break;
                }else{
                    phi[i*pri[j]]=phi[i]*phi[pri[j]];
                }
            }
        }
        for(int i=1;i<=n;++i) phi[i]+=phi[i-1];
        n=read(); k=read(); bl=sqrt(n); 
        Str[1][1]=1; 
        rep(i,2,50){
            rep(j,1,i){
                Str[i][j]=Str[i-1][j]*j+Str[i-1][j-1];
            }
        }
        for(int l=1,r;l<=n;l=r+1){
            R[++tot]=n/l; r=n/R[tot];
            f[tot]=S(R[tot],k)-1;
            num[tot]=R[tot]-1;
            // Do not consider ones so subtract them
            if(R[tot]<=bl) id1[R[tot]]=tot; else id2[n/R[tot]]=tot;
        }
        for(int j=1;j<=cnt;++j){
            uint now=ksm(pri[j],k);
            sum[j]=sum[j-1]+now;
            for(int i=1;i<=tot&&1ll*pri[j]*pri[j]<=R[i];++i){
                int pos=getid(R[i]/pri[j]);
                f[i]-=(f[pos]-sum[j-1])*now;
                res[i]+=f[pos]-sum[j-1];
                num[i]-=num[pos]-(j-1); // Numbers except from primes
            }
        }
        uint ans=0;
        for(int l=1,r;l<=n;l=r+1){
            r=n/(n/l);
            ans+=(2*getphi(n/l)-1)*(calc(r)-calc(l-1));
        }
        print(ans);
        return 0;
    }
    

    代码不附带缺省源,如果需要可以去 【遇到困难睡大觉】 一文中粘贴并去掉 #define int long long

    感觉最近代码越来越蓬松了,都快不可读了

  • 相关阅读:
    任务调度~Quartz.net实现简单的任务调试
    编译器错误~写JS还是谨慎点好
    编译器错误~不能向ObjectStateManager添加相同的键
    EF架构~将数据库注释添加导入到模型实体类中
    c++ pair类型
    Adobe dreamweaver 5.5安装过程
    c++函数作为参数传递
    c++ vector.clear()
    动态规划之装配线调度问题
    转:VS后缀名详解
  • 原文地址:https://www.cnblogs.com/yspm/p/15742763.html
Copyright © 2011-2022 走看看