2021湘潭邀请赛-正式赛-C-数论分块

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目大意:

让你计算:
∑ i = x 1 x 2 ∑ j = y 1 y 2 ( ⌊ i x 1 ⌋ + ⌊ x 2 i ⌋ + ⌊ j y 1 ⌋ + ⌊ y 2 j ⌋ ) 2 \sum_{i=x_{1}}^{x_{2}} \sum_{j=y_{1}}^{y_{2}}\left(\left\lfloor\frac{i}{x_{1}}\right\rfloor+\left\lfloor\frac{x_{2}}{i}\right\rfloor+\left\lfloor\frac{j}{y_{1}}\right\rfloor+\left\lfloor\frac{y_{2}}{j}\right\rfloor\right)^{2} i=x1x2j=y1y2(x1i+ix2+y1j+jy2)2.

x 1 , y 1 , x 2 , y 2 ≤ 1 e 9 x1,y1,x2,y2 \leq 1e9 x1,y1,x2,y21e9.

题目思路:

展开直接算:
a = 第一部分 , b = 第二部分 , c = 第三部分 , d = 第四部分 a=第一部分,b=第二部分,c=第三部分,d=第四部分 a=第一部分,b=第二部分,c=第三部分,d=第四部分

通过化简可得:
= ∑ ∑ a 2 + b 2 + c 2 + d 2 + 2 ( a b + a c + a d + b c + b d + c d ) =\sum\sum a^2+b^2+c^2+d^2+2(ab+ac+ad+bc+bd+cd) =∑∑a2+b2+c2+d2+2(ab+ac+ad+bc+bd+cd).

∑ ∑ a 2 = d y ∗ ∑ a 2 \sum\sum a^2=dy*\sum a^2 ∑∑a2=dya2. 直接分倍数段计算,然后还要算一个前n项平方的和

∑ ∑ b 2 = d y ∗ ∑ b 2 \sum\sum b^2=dy*\sum b^2 ∑∑b2=dyb2. 整除分块.

c , d 类似 c,d类似 c,d类似

后面一大坨,难点在 a ∗ b 和 c ∗ d a*b和c*d abcd部分.

∑ ∑ a ∗ b = d y ∗ ∑ a ∗ b \sum\sum a*b=dy*\sum a*b ∑∑ab=dyab. 还是整除分块,

设本块的值为 x x x,块的左右端点为 [ L , R ] [L,R] [L,R],差分计算一下 r e s = ∑ i = L R ⌊ i x 1 ⌋ res=\sum_{i=L}^{R}\lfloor\frac{i}{x_1}\rfloor res=i=LRx1i.本块的贡献即为 x ∗ r e s x*res xres.

其他的项直接乘起来即可.

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
int a[maxn];
ll ksm (ll a , ll b){ ll ans = 1 , base = a;
while (b){if (b & 1) ans = ans * base % mod;b >>= 1;base = base * base % mod;}return ans;}
ll inv6 = ksm(6 , mod - 2);
ll inv2 = ksm(2 , mod - 2);
ll x1 , x2 , y1 , y2;
ll calc (ll n)
{
    return n * (n + 1) % mod * inv2 % mod;
}
ll calc2 (ll n)
{
    return n * (n + 1) % mod * ((2 * n + 1) % mod) % mod * inv6 %mod;
}
ll cal_i_x1_2 (ll x1 , ll x2)
{
    ll rest = x2 % x1 + 1;
    ll up = x2 / x1;
    // [1 , up - 1] 每个出现 x1次
    ll ans = calc2(up - 1) * x1 % mod;
    // up 出现 rest次
    ans = (ans + rest * up %mod * up % mod) % mod;
    return ans;
}
ll cal_x2_i_2 (ll x1 , ll x2){
    ll ans = 0;
    for (ll l = x1 , r ; l <= x2 ; l = r + 1){
        r = x2 / (x2 / l);
        ll v = x2 / l;
        // [l , r] 都是 v
        ans = (ans + (r - l + 1) * v % mod * v % mod) % mod;
    }
    return ans;
}

ll cal_i_x1 (ll x1 , ll x2)
{
    ll rest = x2 % x1 + 1;
    ll up = x2 / x1;
    // [1 , up - 1] 每个出现 x1次
    ll ans = calc(up - 1) * x1 % mod;
    // up 出现 rest次
    ans = (ans + rest * up %mod) % mod;
    return ans;
}
ll cal_ab (ll x1 , ll x2)
{
    ll ans = 0;
    for (ll l = x1 , r ; l <= x2 ; l = r + 1){
        r = x2 / (x2 / l);
        ll v = x2 / l;
        ll f = cal_i_x1(x1 , r) - cal_i_x1(x1 , l - 1);
        f = (f + mod) % mod;
        ans = (ans + v * f%mod) % mod;
    }
    return ans;
}
ll cal_x2_i (ll x1 , ll x2)
{
    ll ans = 0;
    for (ll l = x1 , r ; l <= x2 ; l = r + 1){
        r = x2 / (x2 / l);
        ll v = x2 / l;
        ans = (ans + v * (r - l + 1)%mod) % mod;
    }
    return ans;
}
ll solve ()
{
    ll a , b , c , d;
    ll dx = x2 - x1 + 1 , dy = y2 - y1 + 1;
    a = cal_i_x1(x1 , x2);
    b = cal_x2_i(x1 , x2);
    c = cal_i_x1(y1 , y2);
    d = cal_x2_i(y1 , y2);
    vector<ll> ans;
    ans.pb(dy * cal_i_x1_2(x1 , x2)%mod);
    ans.pb(dy * cal_x2_i_2(x1 , x2)%mod);
    ans.pb(dx * cal_i_x1_2(y1 , y2)%mod);
    ans.pb(dx * cal_x2_i_2(y1 , y2)%mod);

    ans.pb(dy * cal_ab(x1 , x2)%mod);
    ans.pb(a * c % mod);
    ans.pb(a * d % mod);
    ans.pb(b * c % mod);
    ans.pb(b * d % mod);
    ans.pb(dx * cal_ab(y1 , y2)%mod);

    ans.pb(dy * cal_ab(x1 , x2)%mod);
    ans.pb(a * c % mod);
    ans.pb(a * d % mod);
    ans.pb(b * c % mod);
    ans.pb(b * d % mod);
    ans.pb(dx * cal_ab(y1 , y2)%mod);
    ll res = 0;
    for (auto &g : ans) res = (res + g) % mod;
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    int t; cin >> t;
    while (t--){
        cin >> x1 >> x2 >> y1 >> y2;
        cout << solve() << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值