2020牛客多校第七场 Dividing(除法分块)

在这里插入图片描述

思路:
题意可以等价为求 ( x , y ) (x,y) 满足 1 x n , 1 y n 1≤x≤n,1≤y≤n ,且 x m o d    y = 0 x m o d    y = 1 x\mod y=0或者x\mod y=1

这个可以对于x=1或者y=1的情况单独考虑,结果为n+k-1。
对于x≥2和y≥2,模数为0的时候,此时其实就是寻找对于[2,k]中每个数为其倍数,在前n个数中存在多少个数为其倍数。

这个过程可以用除法分块解决。对于x,寻找前n个数中有多少个数为其倍数,其实就是 n x \frac{n}{x} 。而除法分块是寻找对于 n / i n/i ,存在多少个 i i 满足这个式子的值相同。

模数为1的时候也是一样,就是将n变成n-1。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <iostream>
#include <map>
#include <string>

using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 5000 + 7;

ll get1(ll n,ll k) {
    ll ans = n;
    ll r = 2,l = 2;
    for(;l <= k;l = r + 1) {
        if(n / l == 0) r = k;
        else r = min(k,n / (n / l));
        ans += n / l % mod * ((r - l + 1) % mod);
        ans %= mod;
    }
    return ans;
}

ll get2(ll n,ll k) {
    ll ans = k - 1;
    ll r = 2,l = 2;
    for(;l <= k;l = r + 1) {
        if(n / l == 0) r = k;
        else r = min(k,n / (n / l));
        ans += n / l % mod * ((r - l + 1) % mod);
        ans %= mod;
    }
    return ans;
}

int main() {
    ll n,k;scanf("%lld%lld",&n,&k);
    ll ans = get1(n,k) + get2(n - 1,k);
    printf("%lld\n",ans % mod);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/107827616