2025牛客寒假算法基础集训营4

A.Tokitsukaze and Absolute Expectation

image

由于每一部分独立不影响,所以可以将题目转化为每一部分的期望和,即ans=E(u=2n|aiai1|)=u=2nE(|aiai1|)
期望就是所有的绝对值除以其个数,个数就是图中矩形的大小,绝对值的和分为图中三个部分。
第一,三部分每一行为等差数列,行与行之间每列的数字均相差一(公式见代码)
第二部分将其拆分出来,拆分为
image

即每一部分为n(n+1),求和即可(高中知识推导Sn)

#include <bits/stdc++.h>  
  
#define lowbit(x) ((x)&(-x))  
#define all(x) x.begin(),x.end()  
#define int long long  
using namespace std;  
const int N = 2e5 + 10;  
const int MOD = 1e9 + 7;  
  
int qp(int a, int b) {  
    int res = 1;  
    while (b) {  
        if (b & 1) {  
            res = res * a % MOD;  
        }  
        a = a * a % MOD;  
        b /= 2;  
    }  
    return res;  
}  
  
int inv(int x) { return qp(x, MOD - 2); }  
  
vector<int> L(N), R(N);  
  
int cal1(int a1, int x, int y) {  
    int res = 0;  
    res += (y * a1 % MOD + y * (y - 1) % MOD * inv(2) % MOD) % MOD * x % MOD;  
    res %= MOD;  
    res -= x * (x - 1) % MOD * inv(2) % MOD * y % MOD;  
    res = (res + MOD) % MOD;  
    return res;  
}  
  
int cal2(int la, int ra, int lb, int rb) {  
    if (la > rb || lb > ra) return 0;  
    int l = max(la, lb);  
    int r = min(ra, rb);  
    int n = r - l + 1;  
    return 1LL * (n - 1) * n % MOD * (n + 1) % MOD * inv(3) % MOD;  
}  
  
int cal(int la, int ra, int lb, int rb) {  
    int res = 0;  
    int res1 = 0;  
    int res2 = 0;  
    int res3 = 0;  
    if (la > lb) {  
        swap(la, lb);  
        swap(ra, rb);  
    }  
  
    res1 = cal1(lb - la, min(ra + 1, lb) - la, rb - lb + 1);  
    res += res1;  
//    cerr<<"res1="<<res1<<"\n";  
    res %= MOD;  
    res2 = cal2(la, ra, lb, rb);  
    res += res2;  
//    cerr<<"res2="<<res2<<"\n";  
    res %= MOD;  
    if (ra >= lb) {  
        if (rb > ra) {  
            res3 = cal1(ra - lb + 1, ra - lb + 1, rb - ra);  
        } else if (ra > rb) {  
            res3 = cal1(rb - lb + 1, rb - lb + 1, ra - rb);  
        }  
    }  
    res += res3;  
    res %= MOD;  
//    cerr<<"res3="<<res3<<"\n";  
    return res;  
}  
  
void solve() {  
    int n;  
    cin >> n;  
    for (int i = 1; i <= n; i++) {  
        cin >> L[i] >> R[i];  
    }  
    int ans = 0;  
    for (int i = 2; i <= n; i++) {  
        int fz = cal(L[i - 1], R[i - 1], L[i], R[i]);  
        int fm = 1LL * (R[i - 1] - L[i - 1] + 1) * (R[i] - L[i] + 1) % MOD;  
        ans = (ans + fz * inv(fm)) % MOD;  
    }  
    cout << ans << '\n';  
}  
  
signed main() {  
    cin.tie(0);  
    cout.tie(0);  
    ios::sync_with_stdio(0);  
//    cout << fixed << setprecision(15);  
    int _ = 1;  
    cin >> _;  
    while (_--) {  
        solve();  
    }  
    return 0;  
}

L.Tokitsukaze and XOR-Triangle

a1b1
a1b2a2b2
a1b3a2b3a3b3
a1b4a2b4a3b4a4b4
a1b5a2b5a3b5a4b5a5b5
a1b6a2b6a3b6a4b6a6b6
每一个ai都要不会和自身下标前的bj进行运算,所以可以预先处理所有ai和后面所有的bj运算,即aisufb[i+1],那么就得到了每一列的数据,可以预处理前i列的数据,类前缀和即可得出中间lr列的和,最后在减去多余的最后几行即可。例如要得到[2,4],先得到sum[4]sum[1],再减去(prea[4]prea[1])sufb[5]。处理时按二进制位逐位处理即可。

#include <bits/stdc++.h>

#define lowbit(x) ((x)&(-x))
#define all(x) x.begin(),x.end()
#define int int
using namespace std;
const int N = 1e3 + 10;
const int MOD = 1e9 + 7;



void solve() {
    int n,q;
    cin >> n >> q;
    
    vector<vector<int>> pre_a1(31, vector<int>(n + 1));
    vector<vector<int>> pre_a0(31, vector<int>(n + 1));
    vector<vector<int>> suf_b0(31, vector<int>(n + 2));
    vector<vector<int>> suf_b1(31, vector<int>(n + 2));
    vector<vector<int>> pre_a1_b0(31, vector<int>(n + 1));
    vector<vector<int>> pre_a0_b1(31, vector<int>(n + 1));
    vector<int> a(n + 1), b(n + 1);
    
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) cin >> b[i];

    for (int k = 0; k <= 30; ++k) {
        suf_b0[k][n + 1] = 0;
        suf_b1[k][n + 1] = 0;
        for (int i = n; i >= 1; --i) {
            int bit = (b[i] >> k) & 1;
            suf_b0[k][i] = suf_b0[k][i + 1] + (bit == 0 ? 1 : 0);
            suf_b1[k][i] = suf_b1[k][i + 1] + bit;
        }

        pre_a1[k][0] = 0;
        pre_a0[k][0] = 0;
        for (int i = 1; i <= n; ++i) {
            int abit = (a[i] >> k) & 1;
            pre_a1[k][i] = pre_a1[k][i - 1] + abit;
            pre_a0[k][i] = pre_a0[k][i - 1] + (abit == 0 ? 1 : 0);
        }

        pre_a1_b0[k][0] = 0;
        pre_a0_b1[k][0] = 0;
        for (int i = 1; i <= n; ++i) {
            int a1 = (a[i] >> k) & 1;
            pre_a1_b0[k][i] = pre_a1_b0[k][i - 1] + a1 * suf_b0[k][i];
            int a0 = (a[i] >> k) & 1 ? 0 : 1;
            pre_a0_b1[k][i] = pre_a0_b1[k][i - 1] + a0 * suf_b1[k][i];
        }
    }

    while (q--) {
        int l, r;
        cin >> l >> r;
        int ans = 0;
        for (int k = 0; k <= 30; ++k) {
            int sum1 = pre_a1_b0[k][r] - pre_a1_b0[k][l - 1];
            int sum_a1 = pre_a1[k][r] - pre_a1[k][l - 1];
            int sb0_r = suf_b0[k][r + 1];
            int ex1 = sum_a1 * sb0_r;
            int part1 = (sum1 - ex1) % MOD;

            int sum2 = pre_a0_b1[k][r] - pre_a0_b1[k][l - 1];
            int sum_a0 = pre_a0[k][r] - pre_a0[k][l - 1];
            int sb1_r = suf_b1[k][r + 1];
            int ex2 = sum_a0 * sb1_r;
            int part2 = (sum2 - ex2) % MOD;

            int res = (part1 + part2) % MOD;
            res = (res + MOD) % MOD;
            ans = (ans + (res * (1LL << k)) % MOD) % MOD;
        }
        ans = (ans + MOD) % MOD;
        cout << ans << '\n';
    }
}

signed main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
//    cout << fixed << setprecision(15);
    int _ = 1;
    cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}
posted @   yoez123  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示