[数论]余数之和(数论分块)

可能会有点用,另外quickpow常数有点大啊,如果用的都是一样的一定要提前计算。
http://www.51nod.com/Challenge/Problem.html#!#problemId=1225

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7, mod2 = 998244353, inf = 0x3f3f3f3f;

ll quickpow(ll x, ll k)
{
    ll res = 1;
    while(k){
        if(k & 1) res = (res * x) % mod;
        k >>= 1, x = (x * x) % mod;
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    ll n;
    cin >> n;
    ll ans = 0, inv2 = quickpow(2, mod - 2);
    for (ll l = 1, r; l <= n; l = r + 1){
        r = n / (n / l);
        ans -= (n / l) % mod * ((l + r) % mod) % mod * ((r - l + 1) % mod) % mod * inv2 % mod;
    }
    ans = n % mod * (n % mod) + ans;
    ans %= mod; ans += mod; ans %= mod;
    cout << ans << endl;
    return 0;
}

应用
https://www.luogu.org/problemnew/show/P2260
注意一下n和m有没有提出来啊没提出来就不用乘了啊sb啊因为已经计算过了啊这种要取模的题真麻烦很难找错。
另外注意一下模数是否为质数,不是请使用欧拉定理,再不互质请使用扩展欧拉定理,可能会有些毒瘤出题人。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 19940417;
ll quickpow(ll x, ll k)
{
    ll res = 1;
    while(k){
        if(k & 1) res = (res * x) % mod;
        k >>= 1, x = (x * x) % mod;
    }
    return res;
}
ll euler(ll x)
{
    ll res = x;
    for(ll i = 2; i * i <= x; ++i){
        if(x % i == 0){
             res = res / i * (i - 1);
             while(x % i == 0) x /= i;
         }
    }
    if(x > 1) res = res / x * (x - 1);
    return res;
}
ll inv6;
ll sum1(ll l, ll r)
{
    return (l + r) * (r - l + 1) / 2 % mod;
}
ll sum2(ll x)
{
    return x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}
int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    inv6 = quickpow(6, euler(mod) - 1);
    ll n, m;
    cin >> n >> m;
    if (n > m) swap(n, m);
    ll sn = n * n % mod, sm = m * m % mod, sum = 0;
    //\sum_{i = 1}^{n} (n / i) * i
    for (ll l = 1, r; l <= n; l = r + 1){
        r = n / (n / l);
        sn -= (n / l) * sum1(l, r) % mod;
        sn = (sn % mod + mod) % mod;
    }
    //\sum_{i = 1}^{m} (m / i) * i
    for (ll l = 1, r; l <= m; l = r + 1){
        r = m / (m / l);
        sm -= (m / l) * sum1(l, r) % mod;
        sm = (sm % mod + mod) % mod;
    }
    //\sum_{i = 1}^{n} (n / i) * (m / i) * i^2 - ((m * (n / i) + n * (m / i)) * i)
    for (ll l = 1, r; l <= n; l = r + 1){
        r = min(n / (n / l), m / (m / l));
        sum += (m / l) * (n / l) % mod * (sum2(r) - sum2(l - 1)) % mod;
        sum -= (m * (n / l) % mod + n * (m / l) % mod) * sum1(l, r) % mod;
        sum = (sum % mod + mod) % mod;
    }
    ll ans = sn * sm % mod - (n * n % mod * m % mod + sum);
    ans = (ans % mod + mod) % mod;
    cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值