大力出奇迹
∑ i = l r x % ( k ∗ i ) = ∑ i = l r ( x − ( k ∗ i ) ∗ ⌊ x k ∗ i ⌋ ) = x ∗ ( r − l + 1 ) − ∑ i = l r ( k ∗ i ) ∗ ⌊ x / k i ⌋ \displaystyle \sum^{r}_{i=l}{x \% (k*i)}= \displaystyle \sum^{r}_{i=l}{(x-(k*i)*\lfloor \frac{x}{k*i} \rfloor)}\\=x*(r-l+1)-\displaystyle \sum^{r}_{i=l}{(k*i)*\lfloor \frac{x/k}{i}\rfloor} i=l∑rx%(k∗i)=i=l∑r(x−(k∗i)∗⌊k∗ix⌋)=x∗(r−l+1)−i=l∑r(k∗i)∗⌊ix/k⌋
后边 ∑ i = l r ( k ∗ i ) ∗ ⌊ x / k i ⌋ \displaystyle \sum^{r}_{i=l}{(k*i)*\lfloor \frac{x/k}{i}\rfloor} i=l∑r(k∗i)∗⌊ix/k⌋就是除法分块的部分。
⌊ x / k i ⌋ \lfloor \frac{x/k}{i}\rfloor ⌊ix/k⌋在一段连续 [ i ] [ i ] [i]区间是相同的
所以我们枚举 L L L 令: t = ⌊ x / k L ⌋ t=\lfloor \frac{x/k}{L}\rfloor t=⌊Lx/k⌋
然后找到 t t t 相同的区间右端点 R R R: R = t = = 0 ? r : m i n ( x / k / t , r ) R= t==0 \ ? \ r \ : \ min(x/k/t, r) R=t==0 ? r : min(x/k/t,r)
这一块的值就是: t ∗ k ∗ ( R − L + 1 ) ∗ ( R + L ) / 2 t*k*(R-L+1)*(R+L)/2 t∗k∗(R−L+1)∗(R+L)/2:就是把相同的 t 和 k 提出来,后边是连续区间 i 相加,也就是差值为1的等差序列求和。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll ;
ll read()
{
ll x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 20;
const int maxM = 1003;
const ll mod = 1e9 + 7;
ll fpow(ll x, ll y) {
ll ans = 1, base = x;
while(y) {
if(y & 1)
ans *= base, ans %= mod;
base *= base, base %= mod;
y >>= 1;
}
return ans;
}
ll L, R, x, k;
int main()
{
int T; cin >> T;
while(T -- ) {
L = read(), R = read(), x = read(), k = read();
ll ans = (R - L + 1) * x % mod; x /= k;
for(ll l = L, r, t; l <= R; l = r + 1) {
t = x / l;
r = t ? min(x / t, R) : R;
ans -= t * k * (r - l + 1) * (l + r) % mod * fpow(2, mod - 2) % mod;
ans = (ans % mod + mod) % mod;
}
cout << ans % mod << endl;
}
return 0;
}
基础除法分块:
P2261 [CQOI2007]余数求和
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll ;
ll read()
{
ll x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 20;
const int maxM = 1003;
const ll mod = 1e9 + 7;
ll n, k;
int main()
{
n = read(), k = read();
ll ans = n * k;
for(ll l = 1, r, t; l <= n; l = r + 1 ) {
t = k / l;
r = t ? min(k / t, n) : n;
ans -= t * (r - l + 1) * (r + l) >> 1;
}
cout << ans << endl;
return 0;
}