51nod 1220 约数之和
题目
求
首先有个结论
证明?这结论是我百度的。
可以类比下
然后
然后我们代入
因为
处理下
等差数列求和带走
回代
消掉一些东西并整理下,比如
然后倍数的套路一波
单独拆来看,首先第一个是可以杜教筛的。
怪怪的,我们记
那么
我们发现
这个东西就是
那么就是
那么
再用这个
不太会了 qwq
试试把等差数列求和还回去
枚举
咋又是你!
回代
发现有
记
那么
然后杜教筛()
对于
可以整除分块预处理一部分,再在需要的时候再整除分块。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#define N (int)(1.6e5+5)
#define ll long long
#define mod (int)(1e9+7)
using namespace std;
ll lrd() {
ll f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
bool vis[N];
int pri[N>>2],tot;
ll mu[N],ans_d[N];
map<ll,ll>ans_mu;
ll SUM1(ll x) {
x%=mod;
return (x*(x+1)/2)%mod;
}
void init() {
mu[1]=1;
for(int i=2;i<N;i++) {
if(!vis[i]) pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<N;j++) {
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<N;i++) mu[i]=(mu[i-1]+i*mu[i])%mod;
for(int n=1;n<N;n++) {
for(int l=1,r;l<=n;l=r+1) {
r=n/(n/l);
ans_d[n]+=(SUM1(r)-SUM1(l-1))*(n/l);
ans_d[n]%=mod;
}
}
}
ll fpow2(ll x) {
x%=mod;
return x*x%mod;
}
ll get_mu(ll x) {
if(x<N) return mu[x];
if(ans_mu[x]) return ans_mu[x];
ll ans=1;
for(ll l=2,r;l<=x;l=r+1) {
r=x/(x/l);
ans-=(SUM1(r)-SUM1(l-1))*get_mu(x/l)%mod;
ans%=mod;
}
return ans_mu[x]=ans;
}
ll get_d(ll x) {
if(x<N) return ans_d[x];
ll ans=0;
for(ll l=1,r;l<=x;l=r+1) {
r=x/(x/l);
ans+=(SUM1(r)-SUM1(l-1))*(x/l)%mod;
ans%=mod;
}
return ans;
}
int main() {
init();
ll ans=0,n=lrd();
for(ll l=1,r;l<=n;l=r+1) {
r=n/(n/l);
ans+=(get_mu(r)-get_mu(l-1))*fpow2(get_d(n/l))%mod;
ans%=mod;
}
ans=(ans%mod+mod)%mod;
printf("%lld",ans);
return 0;
}