zoukankan      html  css  js  c++  java
  • [余数求和]整除分块

    Description

    给出整数(n,k),计算(G(n,k)=sumlimits_{i=1}^n=k mod i),(1<=n,k<=1e9)

    Solution

    将k mod i展开可以得到
    (k - i*lfloor frac{k}{i} floor)
    将求和式子展开可以得到
    (sumlimits_{i=1}^n=n*k-sumlimits_{i=1}^n i*lfloorfrac{k}{i} floor)
    利用整除分块,可以发现,对于相同的(lfloorfrac{k}{i} floor),即每个区间(l 到 r),每次只需要再对i求和即可
    即每次计算((r-l+1)*lfloor frac{k}{i} floor * (l+r)/2)

    Note

    在分块的时候误写为r=N/(N/i)导致调试耽误大量时间,而且交了四发才发现

    for (ll l = 1, r; l <= N; l = r + 1) {
            if (l > K) {
                break;
            }
            r = min(N, K/(K/l));
            ans -= (r - l + 1)*(K/l)*(l + r)/2;
        }
    

    Code

    //https://www.luogu.com.cn/problem/P2261
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <set>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define debug cout<<0<<endl
    #define ll long long
    const int MAXN = 1e2 + 10;
    const int MOD = 1e9 + 7;
    using namespace std;
    
    ll ans = 0;
    
    void solve(ll N, ll K) {
        ans = N*K;
        for (ll l = 1, r; l <= N; l = r + 1) {
            if (l > K) {
                break;
            }
            r = min(N, K/(K/l));
            ans -= (r - l + 1)*(K/l)*(l + r)/2;
        }
        cout << ans;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        ll N, K; cin >> N >> K;
        solve(N, K);
        return 0;
    }
    
  • 相关阅读:
    [NOI Online 2021 提高组] 愤怒的小N
    [NOI Online 2021 提高组] 积木小赛
    「2020-2021 集训队作业」Yet Another Permutation Problem
    无标号有根树/无根树 计数
    无向图的 三元环
    有标号二分图计数
    有标号荒漠计数
    「雅礼集训 2018 Day8」B
    CF708E Student's Camp
    清华集训 2016 选做
  • 原文地址:https://www.cnblogs.com/ez4zzw/p/12898048.html
Copyright © 2011-2022 走看看