Beautiful fountains rows

题目链接

题目大概意思是给n种球,长为m的数轴,给出n个区间,区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]每个点都放上第i种球,让你求出区间长度之和,要求区间内有球,且球的个数为奇数。

这个题如果直接用数据结构我真不会,看网上的都是随机化,给每种球随机一个值,那么我们可以知道,某个区间如果符合要求,那么这个区间每个点的异或值应该 = = == ==这个区间出现的数的异或值。
那么前一个我们可以用前缀和来做,后一个我们还是用前缀和。
首先 p r e pre pre数组表示异或前缀和
a a a数组表示每个点的值
A A A数组表示每个区间以i为左端点出现的数的异或值
d d d数组表示0~i出现过的数的异或值
所以区间 [ L , R ] [L, R] [L,R]如果符合条件那么他就应该满足以下条件
s u m [ R ] ⊕ s u m [ L − 1 ] = = d [ R ] ⊕ d [ L − 1 ] sum[R]\oplus{sum[L - 1]} == d[R]\oplus{d[L - 1]} sum[R]sum[L1]==d[R]d[L1] 其中 d [ L − 1 ] d[L - 1] d[L1] 可以更换为 d [ L ] ⊕ a [ L ] d[L]\oplus{a[L]} d[L]a[L](这里的正确性有待考证)移相可得 s u m [ R ] ⊕ s u m [ L ] = = d [ R ] ⊕ d [ L ] = > s u m [ R ] ⊕ d [ R ] = s u m [ L ] ⊕ d [ L ] sum[R]\oplus{sum[L]} == d[R]\oplus{d[L]} => sum[R]\oplus{d[R]} = sum[L]\oplus{d[L]} sum[R]sum[L]==d[R]d[L]=>sum[R]d[R]=sum[L]d[L]用map记录右边的值,这样就可以找到符合上述等式几个点,这几个点中任意两点都符合上式,也就是要求的区间,求和的话有一个小技巧我们求出(i - 1)的和,将每个点都先乘i再减去前方求的和就是当前点到前方任意一点之间的距离之和。

最后减去空区间,空区间每加入一个点就相当于多加了一个等差数列。
代码:

#include <bits/stdc++.h>
#define solve(x) x*(x + 1)/2
using namespace std;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
ull pre[maxn],a[maxn];
ull A[maxn];
ull d[maxn];
map<ull, long long > mp, mp1;
int main()
{
    srand(998244353);

    int n,m;
    cin >> n >> m;
    for(int i = 0; i < n; i ++){
        int x,y;
        cin >> x >> y;
        ull w=(ull)rand()*rand()*rand()+(ull)rand()*rand();
        a[x]^= w;
        a[y + 1] ^= w;
        A[x] ^= w;
    }

    for(int i = 1; i <= m; i ++){
        a[i] ^= a[i - 1];
        d[i] = d[i - 1] ^ A[i];
        pre[i] = pre[i - 1] ^ a[i];
    }

    ull ans = 0;
    for(int i = 1; i <= m; i ++){
        ull x = pre[i]^d[i];
        mp[x] ++, mp1[x] = mp1[x] + i - 1;
        ans += mp[x]*i - mp1[x];
    }

    for(int i = 1, j = 0; i <= m; i ++){
        if(a[i] == 0) ans -= solve(ull(i - j));
        else j = i;
    }
    cout << ans << endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值