码迷,mamicode.com
首页 > 其他好文 > 详细

简单的数学题

时间:2019-05-02 10:02:50      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:isp   前缀和   register   ++i   +=   bre   ++   stream   简单   

简单的数学题

\(\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\ mod\ p,n\leq 10^{10},5×10^8≤p≤1.1×10^9\)且p为质数。

\[ans=\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)=\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^nij(gcd(i,j)==d)\]

于是设

\[f(d)=\sum_{i=1}^n\sum_{j=1}^nij(gcd(i,j)==d)\]

\[dc(x)=\sum_{i=1}^xi=\frac{(1+x)x}{2}\]

\[F(d)=\sum_{i=1}^n\sum_{j=1}^nij(d|gcd(i,j))=dc(n/d)^2d^2\]

由Mobius反演定理我们有

\[f(d)=\sum_{d|x}dc(n/x)^2x^2\mu(x/d)\]

代入原式,即

\[ans=\sum_{d=1}^nd\sum_{d|x}dc(n/x)^2x^2\mu(x/d)=\]

\[\sum_{x=1}^ndc(n/x)^2x^2\sum_{d|x}d\mu(x/d)\]

显然,后面的函数为积性函数,即\(\mu*id=\phi\),于是

\[\sum_{x=1}^ndc(n/x)^2x^2\varphi(x)\]

注意到\(x^2\)不能整除分块,于是考虑和\(\varphi(x)\)一起维护,所以设\(C(x)=x^2\varphi(x)\),接下来考虑用杜教筛求前缀和,显然只能待定函数法了,于是设\(A=B*C\),所以

\[\sum_{i=1}^nA(i)=\sum_{i=1}^n\sum_{d|i}B(i/d)d^2\varphi(d)\]

为了抵掉分数形式,自然想到令\(B(x)=x^2\),于是我们有

\[\sum_{i=1}^n\sum_{d|i}B(i/d)d^2\varphi(d)=\sum_{i=1}^ni^3=(\frac{(1+n)n}{2})^2\]

于是套杜教筛基本式,我们不难有,设\(S(n)=\sum_{i=1}^nC(i)\)

\[S(n)=(\frac{(1+n)n}{2})^2-\sum_{d=2}^nS(n/d)d^2\]

\(d^2\)前缀和很好处理,进行杜教筛基本操作即可。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
#define control 6000000
using namespace std;
template<class f1,class f2>
struct chain{
    chain *next;f1 x;f2 y;
};
template<class f1,class f2,class f3,const f3 key>
struct unordered_map{
    chain<f1,f2>*head[key],*pt;
    il void insert(f1 x,f2 y){
        pt=new chain<f1,f2>,pt->x=x,pt->y=y;
        x%=key,pt->next=head[x],head[x]=pt;
    }
    il chain<f1,f2>* find(ll x){
        for(pt=head[x%key];pt!=NULL;pt=pt->next)
            if(x==pt->x)return pt;
        return NULL;
    }
};
bool check[control+1];
ll prime[500000],pt,phi[control+1],
    yyb,inv6;
il void prepare();
il ll pow2(ll),djs(ll),dc(ll),
    pow(ll,ll),p2sum(ll),p3sum(ll);
int main(){
    ll n,i,j,ans(0);
    scanf("%lld%lld",&yyb,&n),inv6=pow(6,yyb-2),
        prepare();
    for(i=1;i<=n;i=j+1)
        j=n/(n/i),(ans+=pow2(dc(n/i))*(djs(j)-djs(i-1))%yyb)%=yyb;
    printf("%lld",(ans+yyb)%yyb);
    return 0;
}
il ll pow(ll x,ll y){
    ll ans(1);while(y){
        if(y&1)ans=ans*x%yyb;
        x=x*x%yyb,y>>=1;
    }return ans;
}
il ll p2sum(ll n){
    return n%=yyb,n*(n+1)%yyb*(n*2+1)%yyb*inv6%yyb;
}
il ll p3sum(ll n){
    return n%=yyb,pow2(dc(n));
}
il ll dc(ll n){
    return n%=yyb,(n*(n+1)>>1)%yyb;
}
unordered_map<ll,ll,ll,999931>sxr;
il ll djs(ll n){
    if(n<=control)return phi[n];
    if(sxr.find(n)!=NULL)return sxr.find(n)->y;
    ll i,j,ans(p3sum(n));
    for(i=2;i<=n;i=j+1)
        j=n/(n/i),(ans-=djs(n/j)*(p2sum(j)-p2sum(i-1))%yyb)%=yyb;
    return sxr.insert(n,ans),ans;
}
il ll pow2(ll x){
    return x*x%yyb;
}
il void prepare(){
    ll i,j;check[1]|=phi[1]|=true;
    for(i=2;i<=control;++i){
        if(!check[i])prime[++pt]=i,phi[i]=i-1;
        for(j=1;j<=pt&&prime[j]*i<=control;++j){
            check[i*prime[j]]|=true;
            if(!(i%prime[j])){phi[i*prime[j]]=phi[i]*prime[j];break;}
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }for(i=1;i<=control;++i)
         (((phi[i]*=pow2(i))%=yyb)+=phi[i-1])%=yyb;
}

简单的数学题

标签:isp   前缀和   register   ++i   +=   bre   ++   stream   简单   

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10801586.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!