【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6134
【题目大意】
求$sum_{i=1}^{n}{sum_{j=1}^{i}lceil{frac{i}{j}} ceil}[ (i,j)==1 ]$
【题解】
设 $g(i)=sum_{i=1}^{n}{sum_{j=1}^{i}lceil{frac{i}{j}} ceil}$,$h(i)=sum_{i=1}^{n}{sum_{j=1}^{i}lceil{frac{i}{j}} ceil}[ (i,j)==1 ]$
有 $g(i)=sum_{d|i}{sum_{j=1}^{frac{i}d}lceilfrac{i}{d*j} ceil}[ (i,j*d)==d ]$
$=sum_{d|i}{sum_{j=1}^{frac{i}d}lceilfrac{frac{i}d}{j}} ceil[ (frac{i}d,j)==1 ]$
$=sum_{d|i}h(frac{i}d)$
$=sum_{d|i}h(d)$
所以有$h(i)=sum_{d|i}mu(d)*g(frac{i}d)$
考虑如何计算 $g(i)$
我们发现$i$对于$i$贡献为$1$,$i+1$到$2*i$贡献为$2$,$2*i+1$到$3*i$贡献为$3$……
贡献为区间更新,因此我们可以用差分数列统计,计算出$g(i)$之后,反演计算$h(i)$即可。
【代码】
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1000010;
typedef long long LL;
const LL P=1000000007LL;
int tot,p[N],miu[N],v[N];
void Mobius(int n){
int i,j;
for(miu[1]=1,i=2;i<=n;i++){
if(!v[i])p[tot++]=i,miu[i]=-1;
for(j=0;j<tot&&i*p[j]<=n;j++){
v[i*p[j]]=1;
if(i%p[j])miu[i*p[j]]=-miu[i];else break;
}
}
}
LL sum[N],ans[N];
void AddMod(LL &a,LL b){a+=b;if(a>=P)a-=P;if(a<0)a+=P;}
void Init(int n){
for(int j=1;j<=n;j++){ans[j]++;for(int i=j;i<=n;i+=j)ans[i+1]++;}
for(int i=1;i<=n;i++)AddMod(ans[i],ans[i-1]);
for(int j=1;j<=n;j++){if(miu[j])for(int i=j;i<=n;i+=j)AddMod(sum[i],miu[j]*ans[i/j]);}
for(int i=1;i<=n;i++)AddMod(sum[i],sum[i-1]);
}
int n;
int main(){
Mobius(1000000);
Init(1000000);
while(~scanf("%d",&n))printf("%d
",sum[n]);
return 0;
}