51nod1220约数之和
Time Limit 3s Memory Limit 128KB
Description
σ(x)
表示x的约束和
求
∑ni=1∑nj=1σ(ij)
Input
一个数n(0
<
n
≤109
)
Output
一个数答,对
109+7
取模。
Sample Input
1000
Sample Output
576513341
解题思路
莫比乌斯反演,杜教筛的各种技能
定义
[x]
的取值为1(x为真)否则为0
d|ij 能不能化为一个 d′|j 呢,想到 d|ij 等同于 dgcd(i,d)|j
d|ij要满足 ∃xy=d[x|i][y|j] ,x取 gcd(i,d) 能供给完 [x|i] 也就是说,这时 gcd(y,i)=1 当且仅当 y|j 时 d|ij 成立,即 d|ij↔dgcd(i,d)|j
∴
gcd(i,d)=d′
?
考虑化为
gcd(,)=1
很简单啊,用
id′∗d′
代替i,用
dd′∗d′
代替d
用i代替 id′ ,用d代替 dd′
gcd(i,d)=1 怎么处理呢,想到 ∑d|nμ(d)=[n=1] 那么
∴
设
其实h和g是等价的
∑i=1x12⌊xi⌋(⌊xi⌋+1)=∑i=1x∑j=1⌊xi⌋j(i的出现次数和j的出现次数是一样的)=∑i=1x∑j=1⌊xi⌋i=∑i=1x⌊xi⌋i
∴
我们想, ⌊nd⌋ 只有 2n√ 种
当 i<=n√ 时, i∈[1,n√]
当 i>n√ 时, ni<n√
∴⌊ni⌋ 只有 2n√ 种
对于 i ,有j=max{x|⌊nx⌋=⌊ni⌋}=⌊n⌊ni⌋⌋
所以,分块处理
对于i,有∀j∈[⌊n⌊ni−1⌋⌋+1,⌊n⌊ni⌋⌋]⌊nj⌋=i
只需维护
s(x)=∑xi=1f(x)
即可,
g(⌊ni⌋)
直接算
有
O(n)=∑⌊ni⌋O(ni−−√)=O(n34)
对于S(x)
∑d|nμ(d)=[n=1]
那么
同样,分块处理 ∵⌊n4⌋=⌊⌊n2⌋2⌋ ,所以直接搜会有很多重复的项,哈希判重, O(n)=∑⌊ni⌋O(ni−−√)=o(n34)
预处理前 n23 项,复杂度可降到 O(n23)
总复杂度 O(n34)
#include<cstring>
#include<cstdio>
#include<cctype>
#define N 3001001
#define lim 43007
#define mo 1000000007
#define ny 500000004
using namespace std;
typedef long long ll;
ll n,s[N],sum[lim],hash[lim],mu[N],pr[N];
bool bz[N];
int get(ll x){
int y=(int)(x%lim);
while(hash[y] && hash[y]!=x)y++,y=y==lim?0:y;return y;
}
ll S(ll a){
if(a<N)return s[a];
int x=get(a);
if(hash[x])return sum[x];
hash[x]=a;ll ans=1;
for(ll i=2,j;i<=a;i=j+1){
j=a/(a/i);
ans=(ans-(j+i)%mo*((j-i+1)%mo)%mo*ny%mo*S(a/i)%mo+mo)%mo;
}sum[x]=ans;return ans;
}
ll g(ll a){
ll ans=0;
for(ll i=1,j;i<=a;i=j+1){
j=a/(a/i);
ans=(ans+a/i%mo*((i+j)%mo*((j-i+1)%mo)%mo*ny%mo))%mo;
}return ans;
}
int main(){
s[1]=mu[1]=1;
for(ll i=2;i<N;i++){
if(!bz[i])mu[pr[++pr[0]]=i]=-1;
s[i]=(s[i-1]+mu[i]*i%mo+mo)%mo;
for(int j=1;j<=pr[0] && i*pr[j]<N;j++){
bz[i*pr[j]]=1;mu[i*pr[j]]=-mu[i];
if(i%pr[j]==0){mu[i*pr[j]]=0;break;}
}
}
scanf("%lld",&n);
ll ans=0;
for(ll i=1,j,las=0,now,t;i<=n;i=j+1,las=now){
j=n/(n/i);now=S(j);t=g(n/i);
ans=(ans+(now-las+mo)%mo*t%mo*t%mo)%mo;
}
printf("%lld",ans);
}