【题目链接】 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; }