Atcoder 4142 Xor Sum (双指针)

传送门

题意:
在这里插入图片描述

(1<=n<=1e6)

  • a^b == a+b成立当且仅当对于每一位,a,b中最多只有1个数是1.

  • 大胆推广到[l,r],a[l]+a[l+1]...+a[r]==a[l] xor a[l+1] xor ...a[r]成立当且仅当,对于每一位,这些数最多只有1个是1 。

  • 可以推出,如果区间[l,r]满足条件,那么该区间任何一个子区间都满足条件

  • 所以,[l,r]区间满足条件,那么[l+1,r]区间也满足条件 ,我们可以枚举左端点L,分别计算其能贡献多少个满足条件的区间

  • 我们向右求出最远的求端点R,使得区间[L,R]满足条件,这个区间中,以L为左端点的子区间有R-L+1个。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e6 + 10;
const ll mod = 1e9 + 7;
const ll inf = (ll)4e16+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
    
    while(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
    
    
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
    
    while(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){
    
    x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//给定正整数序列 求满足 a[l]^a[l+1]..^a[r] == a[l]+a[l+1]..+a[r] 的区间个数
//按位考虑 等式等价于 这个区间的这些数满足 每一位 最多只有1个数有1
//如果[l,r]满足条件 那么[l+1,r]也满足条件 且这个区间任何一个子区间也都满足条件
//这就符合单调性了 f(L)表示l开头的区间,最远右端点 f(l)<=f(l+1)
//求出[l,f(l)]长度为n 答案贡献(n)*(n+1)/2
int n;
int a[maxn];
int main()
{
    
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d",a+i);
    }
    int l=1,r=1;
    ll ans=0;
    ll sum=a[1];
    ll pre=a[1];
    while(l<=n && r<=n)
    {
    
    
        while(r+1<=n && sum + a[r+1] == (pre^a[r+1]))//^运算记得括号!!!
        {
    
    
            sum+=a[r+1];
            pre^=a[r+1];
            r++;
        }
        ans+=r-l+1;//l开头的符合条件的区间个数
        sum-=a[l],pre^=a[l];
        l++;
    }
    cout<<ans<<'\n';
    return 0;
}

计算满足条件的区间个数这种问题,对区间单独计数的话基本上都是O(n²)级别的,可以往双指针的方向去想,找出区间满足的单调性,即:[l,r]满足的话,[l+1,r]也满足,枚举左端点计算贡献。

猜你喜欢

转载自blog.csdn.net/qq_46030630/article/details/121336609