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}} 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;
}
原文地址:https://www.cnblogs.com/forever97/p/hdu6134.html