自然数幂求和+杜教筛

自然数幂求和

1.

高斯消元

(观察)可得肯定是一个多项式

推出来前几项 消元就行了

2.

倍增

(from http://blog.csdn.net/werkeytom_ftd/article/details/50741165#reply)

inline ll f(ll x,int y){
    if(x<N&&ff[x][y])return ff[x][y];
    if((it=F[y].find(x))!=F[y].end())return it->second;
    if(!x)return 0;
    if(x&1){ if(x<N)return ff[x][y]=(f(x-1,y)+pw(x,y)+mod)%mod; return F[y][x]=(f(x-1,y)+pw(x,y)+mod)%mod; } ll res=0; for(ll j=0;j<=y;j++) res=(res+pw(x/2,y-j)*C[y][j]%mod*f(x/2,j))%mod; if(x<N)return ff[x][y]=(res+f(x/2,y)+mod)%mod; return F[y][x]=(res+f(x/2,y)+mod)%mod; }

 

//By SiriusRen
#include <map>
#include <cstdio>
using namespace std;
const int N=2500000,mod=1000000007;
typedef long long ll;
ll ans,n;
int C[15][15],k,ff[N][6],tot,phi[N],vis[N],prime[N];
map<ll,ll>mp,F[6];map<ll,ll>::iterator it;
void shai(){
    phi[1]=1;
    for(ll i=2;i<N;i++){
        if(!vis[i])prime[++tot]=i,phi[i]=i-1;
        for(ll j=1;i*prime[j]<N&&j<=tot;j++){
            phi[i*prime[j]]=phi[i]*(prime[j]-1),vis[i*prime[j]]=1;
            if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
        }(phi[i]+=phi[i-1])%=mod;
    }
}
inline ll pw(ll x,ll y){
    ll res=1;x%=mod;
    while(y){
        if(y&1)res=res*x%mod;
        x=x*x%mod,y>>=1;
    }return res;
}
ll get_phi(ll x){
    if(x<N)return phi[x];
    if((it=mp.find(x))!=mp.end())return it->second;
    ll res=((x%mod)*((x+1)%mod))%mod*pw(2,mod-2)%mod;
    for(ll i=2,last;i<=x;i=last+1)
        last=x/(x/i),res=(res-get_phi(x/i)*((last-i+1)%mod))%mod;
    return mp[x]=(res+mod)%mod;
}
inline ll f(ll x,int y){
    if(x<N&&ff[x][y])return ff[x][y];
    if((it=F[y].find(x))!=F[y].end())return it->second;
    if(!x)return 0;
    if(x&1){
        if(x<N)return ff[x][y]=(f(x-1,y)+pw(x,y)+mod)%mod;
        return F[y][x]=(f(x-1,y)+pw(x,y)+mod)%mod;
    }
    ll res=0;
    for(ll j=0;j<=y;j++)
        res=(res+pw(x/2,y-j)*C[y][j]%mod*f(x/2,j))%mod;
    if(x<N)return ff[x][y]=(res+f(x/2,y)+mod)%mod;
    return F[y][x]=(res+f(x/2,y)+mod)%mod;
}
signed main(){
    shai(),scanf("%lld%d",&n,&k);
    for(int i=0;i<=10;i++){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;j++)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    for(ll i=1,last;i<=n;i=last+1)
        last=n/(n/i),ans=(ans+(f(last,k)-f(i-1,k)+mod)*(get_phi(n/i)*2-1))%mod;
    printf("%lld\n",ans);
}

 


O(k2lognlogk)

转载于:https://www.cnblogs.com/SiriusRen/p/6680642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值