设g(n)=∑ni=1∑ij=1ceiling(ij)
g(n/3)=∑n/3i=1∑ij=1ceiling(ij)=∑n/3i=1∑ij=1ceiling(3i3j)
显然gcd(3i,3j)>=3,g(n)−g(n/3)=∑ni=1∑ij=1{ceiling(ij)∗[gcd(i,j)!=3∗k]}
这样,答案就显而易见了...
f(n)=∑ni=1μ(i)g(i)
f(n)−f(n−1)=∑[μ(i)g(n/i)−μ(i)g((n−1)/i)]
f(n)=f(n−1)+∑μ(i)[g(n/i)−g((n−1)/i)]
用莫比乌斯搞一下
而g(n)的求解
设ceiling(i/j)=k,枚举j,k
当ceiling(i/j)=k时,i的可能范围为[j∗(k−1)+1,j∗k]
而显然,当j固定时,k可能的值在[1,n/j]之间,O(n/1+n/2+n/3+...+1)=O(n∗(1+1/2+1/3+...+1/n))=O(n∗ln(n+1))
区间线段树给[j∗(k−1)+1,j∗k]区间+k,复杂度为O(n∗ln(n+1)∗log(n))
而如果t[i]=下标i为起点,[i,n]内的元素全部加上t[i]
当t[(k−1)∗j+1]+=k,t[(k∗j+1)]−=k,表示(k−1)∗j+1作为起点全部+k,(k∗j+1)作为起点全部−k
g(i)=∑ij=1t[i],骚操作一下,复杂度减少一个log(n)
#include<stdio.h>
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define MEM(a,x) memset(a,x,sizeof(a))
#define lowbit(x) ((x)&-(x))
using namespace std;
const int inf=1e9+7;
const int N = 1e6 + 50;
namespace Moblus{
const int maxn = N;
bool check[maxn+10];
int prime[maxn+10];
int mu[maxn+10];
void Moblus(){
MEM(check,0);
mu[1]=1;
int tot=0;
for(int i=2;i<=maxn;++i){
if(!check[i]){
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0;j<tot;++j){
if((ll)i*prime[j]>maxn){
break;
}
check[i*prime[j]]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
else{
mu[i*prime[j]]=-mu[i];
}
}
}
}
}
ll g[N],t[N];
void getG(int n){//g[n]= sum(i/j向上取整)
for(int j=1;j<=n;++j){//枚举j
for(int k=1,ed=n/j+(n%j>0);k<=ed;++k){//枚举k,向上取整(i/j)=k
int a=(k-1)*j+1;//a/j=k
int b=(k*j+1);//b/j=k+1
a=min(max(a,j),n+1);//当a,b<j时,全部操作到j上,避免往前累加
b=min(max(b,j),n+1);
t[a]=(t[a]+k)%inf;
t[b]=(t[b]-k)%inf;
}
t[j]=(t[j]+t[j-1])%inf;
g[j]=t[j];//g[j]=t[1]+t[2]+..+t[j]
}
for(int i=1;i<=n;++i){
g[i]+=g[i-1];
g[i]%=inf;
}
}
ll ans[N];
void slove(int n){
Moblus::Moblus();
getG(n);
for(int i=1;i<=n;++i){
for(int j=i;j<=n;j+=i){
ans[j]+=Moblus::mu[i]*(g[j/i]-g[j/i-1])%inf;
ans[j]%=inf;
}
}
for(int i=1;i<=n;++i){
ans[i]=(ans[i]+ans[i-1])%inf;
}
}
int main()
{
//freopen("/home/lu/code/r.txt","r",stdin);
//freopen("/home/lu/code/w.txt","w",stdout);
slove(1e6+1);
int n;
while(~scanf("%d",&n)){
printf("%lld\n",(ans[n]+inf)%inf);
}
return 0;
}