HDU 6134

题意略。

思路:

我们先不考虑[(i , j) == 1],在此情况下,其实这个值是sum( [ (i , j) == 1,2,3,....,n ] ) 这些情况。我们要求的仅仅是其中的第一部分而已。也即:

F(1) = f(1) + f(2) + f(3) + .... + f(n)。[1,2,3,....,n 是1的整数倍]

在这里,我们令 g(i) 为 i / 1 + i / 2 + .... + i / i 向下取整之和。令 G(i) 为 左式向上取整之和,我们有一个递推公式:

g(i) = G(i) - i + cnt[i]     G(i) = g(i - 1) + i    

其中cnt[i]记录的是 i 的因子个数。

我们要想求出在 n 条件下的 F(1),则F(1) = G(1) + G(2) + ... + G(n)。这个我们可以用一个sum预先存下前缀和。而F(2) = G(2) + G(4) + ...

也即G(1) + G(2) + ... + G(n / 2)。

这里可以用莫比乌斯反演。

但是如果每个询问都从1~n这样计算反演,那么由于样例太多,会超时。那么我们可以考虑加一个sqrt(n)的优化。

详见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 1000005;
const LL mod = 1e9 + 7;

LL F[maxn],f[maxn],cnt[maxn],sum[maxn];
LL n;
bool check[maxn];
LL prime[maxn],mu[maxn];
LL sum_mu[maxn];

void mobius(){
    memset(check,false,sizeof(check));
    mu[1] = 1;
    sum_mu[1] = 1;
    int tot = 0;
    for(LL i = 2;i < maxn;++i){
        if(!check[i]){
            prime[tot++] = i;
            mu[i] = -1;
        }
        for(int j = 0;j < tot;++j){
            if(i * prime[j] > maxn) break;
            check[i * prime[j]] = true;
            if(i % prime[j] == 0){
                mu[i * prime[j]] = 0;
                break;
            }
            else mu[i * prime[j]] = -mu[i];
        }
        sum_mu[i] = mu[i] + sum_mu[i - 1];
    }
}
void init(){
    for(LL i = 1;i < maxn;++i){
        for(LL j = 1;i * j < maxn;++j){
            ++cnt[i * j];
        }
    }
    f[1] = F[1] = 1;
    for(LL i = 2;i < maxn;++i){
        F[i] = f[i - 1] + i;
        F[i] %= mod;
        f[i] = (F[i] - i + cnt[i] + mod) % mod;
    }
    for(int i = 1;i < maxn;++i){
        sum[i] = F[i] + sum[i - 1];
    }
}

int main(){
    init();
    mobius();
    while(scanf("%lld",&n) == 1){
        LL ans = 0;
        LL last = 0;
        for(LL i = 1;i <= n;i = last + 1){
            last = n / (n / i);
            ans += (sum_mu[last] - sum_mu[i - 1]) * sum[n / i];
            ans = (ans + mod) % mod;
            //printf("sum[%d / %d] == %lld\n",n,i,sum[n / i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/tiberius/p/9322079.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值