P2424 约数和

题目链接

思路:

首先很容易想到算 i 的贡献,比如 [ L , R] = [5 , 15] , 那么数字 3 在这段区间的贡献c次数就是 15 / 3 - (5 - 1) / 3 = 4

所以可以:

  int l , r;
    cin >> l >> r;
    l --;
    int ans = 0;
    for(int i = 1 ; i <= r ; i ++){
        ans += i * (r / i - (l / i));
    }
    cout << ans << '\n';

但是这个只能拿60,由于 r 太大了,所以:

 

 

 

 B部分我没找到规律,直接用二分找了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define pb push_back
const int maxn = 1e6 + 10;
const int mod = 998244353;
using namespace std;

int cal(int l , int r)
{
    if(l > r)swap(l , r);
    int a = (r + 1) * r / 2;
    int b = (l - 1) * l / 2;
    return a - b;
}
int Get(int left , int up , int value)
{
    int l = left;
    int r = up;
    while(l < r){
        int mid = (l + r) >> 1;
        if(up / mid != value){
            r = mid - 1;
        }
        else{
            l = mid;
            if((l + r >> 1) == l){
                if(up / r == value) l = r;
                else r = l;
            }
        }
    }
    return l;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int l , r;
    cin >> l >> r;
    l --;
    int ans1 = 0 , ans2 = 0;
    for(int i = 1 ; i <= r ; i ++){
        int now = r / i;
        int re = Get(i , r , now);
        ans1 += cal(re , i) * now;
        i = re;
    }
    for(int i = 1 ; i <= l ; i ++){
        int now = l / i;
        int re = Get(i , l , now);
        ans2 += cal(re , i) * now;
        i = re;
    }
    cout << ans1 - ans2 << '\n';
    return 0;
}
/*
    12 / 1 = 12
    12 / 2 = 6
    12 / 3 = 4
    12 / 4 = 3
    12 / 5~6 = 2
    12 / 7 ~ 12 = 1

    9 / 1 = 9 
    9 / 2 = 4
    9 / 3 = 3
    9 / 4 = 2
    9 / 5~9 = 1
    
    4 / 1 = 4
    4 / 2 = 2 
    4 / 3~4 = 1
*/

 

posted @ 2021-01-18 16:00  GoodVv  阅读(41)  评论(0编辑  收藏  举报