【除法分块】power oj 2886

大力出奇迹

∑ 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=lrx%(ki)=i=lr(x(ki)kix)=x(rl+1)i=lr(ki)ix/k

后边 ∑ i = l r ( k ∗ i ) ∗ ⌊ x / k i ⌋ \displaystyle \sum^{r}_{i=l}{(k*i)*\lfloor \frac{x/k}{i}\rfloor} i=lr(ki)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 tk(RL+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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/107198018
OJ