bzoj3601 一个人的数论 (拉格朗日插值求系数)

题目链接:bzoj3601 一个人的数论

Description

有一天hjy96想到了一个数论问题:

对于一个非负整数d和一个正整数n,定义fa(n)为所有小于n且与n互质的正整数的d次方之和。如\(f_3(10) = 1^3+3^3+7^3+ 9^3\)

现给定d,n,求fa(n)的值。输出答案对\(10^9+7\)取模后的结果。

hjy96当然知道怎么做啦!但是他想考考你.....

Input

由于n可能很大,我们给出n的质因数分解式。
\[ n=\prod\limits_{i=1}^wp_i^{\alpha_i} \]
第一行有用空格隔开的一个非负整数d,一个正整数w。

接下来w行,每行有两个用空格隔开的正整数\(p_i,\alpha_i\)。(保证\(p_i\)为素数且互不相同)

Output

一行,一个非负整数表示\(f_d(n)\)\(10^9+7\)取模后的结果。

Sample Input

3 2
2 1
5 1

Sample Output

1100

数据范围与约定

对于所有数据 \(1\le d\le 100,1 \le w \le 1000,2 \le p_i \le 10^9,1 \le \alpha_i \le 10^9.\)

Solution

由题可知
\[ ans=\sum\limits_{i=1}^n[gcd(i,n)=1]i^d \]
推一下
\[ ans=\sum\limits_{i=1}^n[gcd(i,n)=1]i^d\\ =\sum\limits_{i=1}^n\sum\limits_{t|x且t|n}\mu(t)i^d\\ =\sum\limits_{t|n}\mu(t)\sum\limits_{i=1}^{\frac{n}{t}}(i\times t)^d\\ =\sum\limits_{t|n}\mu(t)t^d\sum\limits_{i=1}^{\frac{n}{t}}i^d\\ \]

\(\sum\limits_{i=1}^{\frac{n}{t}}i^d可以表示为一个关于\frac{n}{t}的d+1次多项式\sum\limits_{i=0}^{d+1}f_i(\frac{n}{t})^i\)
\(f_i\)可以用拉格朗日插值或高斯消元求出(我用的是拉格朗日)​

\[ \therefore ans=\sum\limits_{t|n}\mu(t)t^d\sum\limits_{i=0}^{d+1}f_i(\frac{n}{t})^i\\ =\sum\limits_{t|n}\mu(t)\sum\limits_{i=0}^{d+1}f_in^it^{d-i}\\ =\sum\limits_{i=0}^{d+1}\sum\limits_{t|n}\mu(t)f_in^it^{d-i}\\ =\sum\limits_{i=0}^{d+1}f_in^i\sum\limits_{t|n}\mu(t)t^{d-i}\\ \]
容易发现\(\sum\limits_{t|n}\mu(t)t^{d-i}\)是一个积性函数

\(F(n)=\sum\limits_{t|n}\mu(t)t^{d-i}\)

则有\(F(n)=\prod\limits_{i=1}^{w}F(p_i^{\alpha_i})\)

\(F(p_i^{\alpha_i})\)显然等于\(1-p_i^{d-i}\)
\[ \therefore ans= \sum\limits_{i=0}^{d+1}f_in^i\prod\limits_{i=1}^{w}(1-p_i^{d-i})\\ \]

Code

#include<bits/stdc++.h>
const int N=1005;
const int mod=1e9+7;
int Pow(int x,int f=mod-2){
    int re=1;
    while(f){
        if(f&1)re=1ll*re*x%mod;
        f>>=1;
        x=1ll*x*x%mod;
    }
    return re;
}
namespace Lagrange{
    int inv[N],f_[N],f[N],y[N],tmp[N];
    void Solve(int n){
        for(int i=1;i<=n;i++){
            int div=1,lst=0;
            for(int j=1;j<=n;j++)
                if(i!=j)div=1ll*div*(mod+i-j)%mod;
            div=1ll*y[i]*Pow(div)%mod;
            for(int j=0;j<n;j++){
                tmp[j]=1ll*(lst+mod-f_[j])*inv[i]%mod;
                f[j]=(f[j]+(1ll*div*tmp[j]%mod))%mod;
                lst=tmp[j];
            }
        }
    }
    void Pre(int d){
        f_[0]=1;
        for(int i=1;i<=d+2;std::swap(f_,tmp),i++){
            tmp[0]=0,inv[i]=Pow(i);
            for(int j=1;j<=i;j++)tmp[j]=f_[j-1];
            for(int j=0;j<=i;j++)tmp[j]=(tmp[j]+(1ll*f_[j]*(mod-i)%mod))%mod;
        }
        for(int i=1;i<=d+2;i++)y[i]=(y[i-1]+Pow(i,d))%mod;
    }
}
int H(int t,int p){
    if(t<0)return (1+mod-Pow(Pow(p,-t)))%mod;
    return (1+mod-Pow(p,t))%mod;
}
int d,w,a[N],p[N],ans=0;
signed main(){
    using namespace Lagrange;
    scanf("%d%d",&d,&w);
    for(int i=1;i<=w;i++)scanf("%d%d",p+i,a+i);
    Pre(d);
    Solve(d+2);
    int pown=1;
    for(int i=1;i<=d+1;i++){
        int tmp=1;
        for(int j=1;j<=w;j++){
            pown=1ll*pown*Pow(p[j],a[j])%mod;
            tmp=1ll*tmp*H(d-i,p[j])%mod;
        }
        ans=(ans+(1ll*f[i]*pown%mod*tmp%mod))%mod;
    }
    printf("%d",ans);
    return 0;
}
posted @ 2019-05-09 15:56 The_KOG 阅读(...) 评论(...) 编辑 收藏