P7156 [USACO20DEC] Cowmistry P 题解

先令 \(k\rightarrow k + 1\)

\(m\) 表示 \(k\) 二进制的最高位的下一位幂次,不难发现 \([0,m), [m,2m)\) 中不能同时选,不然就一定会有 \(2^m> k\)

所以分别考虑每个长度 \(m\) 的段,继续考虑 \(m' = m/2\),如果三个数同时选到了 \([0,m')\) 中那么限制就没有了,在这个区间里任选三个数即可,右边同理,否则一定有一侧选择了两个,另一侧一个。

不失一般性,设右边有一个,左边两个之间是没有约束的,只需要计算出 \(c\) 表示右边每一个数有多少种左边的数与之对应即可,所以对于右边的这一个数 \(\binom{c}{2}\) 就是答案。

我们考虑分治下去,设左右区间分别为 \([l1,r1), [l2,r2)\)

首先如果 \(k\) 这一位上是 \(0\) 的话,强制两边这一位都选择同 0 或同 1,直接递归下去。

否则如果两个这一位相同,那么对后面位没有限制,将左侧的数的个数计入 \(c\) 中递归下去。

终止条件是左侧区间全部都不/存在,如果都不存在,显然结束了,如果都存在,那么右侧所有数对应的 \(c\) 都是一样的,都是 \(k\bmod (r1-l1)\)

时间复杂度 \(O(k\log k)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10, INF = 1e18, mod = 1e9 + 7;
bool Mst;
int n, k, idx, s[N], ans;
PII p[N], tmp[N]; 
int C3(int n) {
    return (__int128)n * (n - 1) * (n - 2) / 6 % mod;
}
int C2(int n) {
    return n * (n - 1) / 2 % mod;
}
bool in(int l, int r) {
    int t = lower_bound(p + 1, p + n + 1, (PII){r, -1}) - p;
    if(t <= n && p[t].x <= l) return 1;
    return 0;
}
int calc(int x) {
    int pos = lower_bound(p + 1, p + n + 1, (PII){x + 1, -1}) - 1 - p;
    if(pos == 0) return 0;
    return s[pos - 1] + min(p[pos].y, x) - p[pos].x + 1; 
}
int calc(int l, int r) {
    return (calc(r) - calc(l - 1));
}
int judge(int l, int r) {
    int t = calc(l, r);
    if(t == r - l + 1) return 1;
    if(t == 0) return 0;
    return -1;
}
void solve(int b, int l1, int r1, int l2, int r2, int coef) {
    // if(l2 == r2) return ;
    // cout << l1 << ' ' << r1 << ' ' << l2 << ' ' << r2 << endl;
    if(judge(l1, r1 - 1) == 0) {
        ans = (ans + calc(l2, r2 - 1) * C2(coef)) % mod;
        return ;
    } 
    if(judge(l1, r1 - 1) == 1) {
        ans = (ans + C2(coef + k % (r2 - l2)) * calc(l2, r2 - 1)) % mod;
        return ;
    }
    int m1 = l1 + r1 >> 1, m2 = l2 + r2 >> 1, L = calc(l1, m1 - 1), R = calc(m1, r1 - 1);
    // cout << k << ' ' << b << ' ' << (k >> b & 1) << '\n';
    if(k >> b & 1) {
        solve(b - 1, l1, m1, m2, r2, coef + R);
        solve(b - 1, m1, r1, l2, m2, coef + L);
    }
    else {
        solve(b - 1, l1, m1, l2, m2, coef);
        solve(b - 1, m1, r1, m2, r2, coef);
    }
}
bool Med;
signed main() {
//    freopen("dat.in", "r", stdin);
    ios::sync_with_stdio(0), cin.tie(0);
    cerr << abs(&Mst - &Med) / 1048576.<< "Mb\n";
    cin >> n >> k, k ++;
    int m = 1;
    while(m <= k) m <<= 1;
    int tot = 0, cnt = 0;
    for(int i = 1; i <= n; i ++) cin >> p[i].x >> p[i].y;
    sort(p + 1, p + n + 1);
    for(int i = 1; i <= n; i ++) {
        if(idx && tmp[idx].y == p[i].x - 1) tmp[idx].y = p[i].y;
        else tmp[++ idx] = p[i];
    }
    swap(n, idx), swap(p, tmp);
    for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + (p[i].y - p[i].x + 1);
    // cout << m << '\n';
    for(int i = 0; i <= p[n].y; i += m) {
        int mid = i + m / 2;
        ans = (ans + C3(calc(i, mid - 1)) + C3(calc(mid, i + m - 1))) % mod;
        solve(__lg(m) - 2, i, mid, mid, i + m, 0);
        solve(__lg(m) - 2, mid, i + m, i, mid, 0);
    }
    cout << ans << '\n';
    
    return 0;
}
posted @ 2025-12-17 16:58  MoyouSayuki  阅读(8)  评论(0)    收藏  举报
:name :name