HDU 6134 Battlestation Operational(莫比乌斯反演)

 

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6134

 

【题目大意】

  求$\sum_{i=1}^{n}{\sum_{j=1}^{i}\lceil{\frac{i}{j}}\rceil}[ (i,j)==1 ]$

 

【题解】

  设 $g(i)=\sum_{i=1}^{n}{\sum_{j=1}^{i}\lceil{\frac{i}{j}}\rceil}$,$h(i)=\sum_{i=1}^{n}{\sum_{j=1}^{i}\lceil{\frac{i}{j}}\rceil}[ (i,j)==1 ]$

  有 $g(i)=\sum_{d|i}{\sum_{j=1}^{\frac{i}d}\lceil\frac{i}{d*j}\rceil}[ (i,j*d)==d ]$

  $=\sum_{d|i}{\sum_{j=1}^{\frac{i}d}\lceil\frac{\frac{i}d}{j}}\rceil[ (\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\n",sum[n]);
    return 0;
}
posted @ 2017-08-18 13:12  forever97  阅读(452)  评论(0编辑  收藏  举报