整除分块 2025牛客寒假算法基础集训营3G
G33 整除分块(数论分块)_哔哩哔哩_bilibili
对于每个i, 1 <= i <= n n / i 下取整的值最多有2 * sqrt(n)种 并且数字x所在块的值为 n / (n / i)
这一题, 每个块中余数是一个以除数为公差的等差数列, 二分第k大的数可能为几即可 , 二分的思路与E题极为相似
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
struct info {
int hi, lo, div;
};
bool cmp(info a, info b) {
return a.hi < b.hi;
}
void solve(){
int n, k;
cin >> n >> k;
map<int, int> next;
for(int i = 1; i <= n; ) {
next[i] = n / (n / i);
i = next[i] + 1;
}
vector<info> a;
for(int i = 1; i <= n;) {
int div = n / i;
int hi = n % i;
int lo = n % next[i];
a.push_back({hi,lo,div});
i = next[i] + 1;
}
ll ans = 0;
auto check = [&] (int x) -> bool {
int cnt = 0;
ll res = 0;
for(auto it : a) {
if(x > it.hi) continue;
int z = (it.hi - max(it.lo, x) ) / it.div + 1;
cnt += z;
res += (it.hi + it.hi - it.div * 1ll * (z - 1)) * z / 2;
}
ans = res - (cnt - k) * x;
return cnt >= k;
};
int lo = -1, hi = n + 1;
while(lo + 1 < hi) {
int mid = lo + hi >> 1;
if(check(mid)) lo = mid;
else hi = mid;
}
check(lo);
cout << ans << endl;
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int T = 1;
//cin >> T;
while(T--) solve();
return 0;
}