南昌邀请赛 网络赛 MORE XOR(规律+前缀异或和)

本文深入探讨了一个复杂的序列查询问题,通过对序列的层级定义和数学分析,提出了一种基于动态规划的线性解决方案。通过对不同长度查询区间的贡献状态分析,详细解释了如何通过递推关系高效计算异或前缀和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://nanti.jisuanke.com/t/38230

题目大意

给定一个序列,层层定义三个函数,

定义都是数学式子很复杂,但是终归就是

每一位的数取还是不取的关系.

题目分析 

第一层:1,1,1,1,1

第二层:1,0,1,0,1,事实上就是上一层前缀和模2,

第三层:1,1,0,0,1,1,0,0,...

到这里即可,

那么分析,对于(l,r)这样的查询区间,

每个数其确定是否贡献的函数,比如如果区间长度是4吧:

1 4

2 3

3 2

4 1

可以知道这四对数没有一对产生贡献,

可以推广到4n长度,与此同时那么4n+1,4n+2,4n+3也可以推断,

分别把右边序列向下偏移一位,

贡献状态分别是:

每四个取第一个数,每四个取第一二个数,每四个取第二个数.

刚开始我还在想着从前往后,但这个序列贡献有点小小的对称思想,

应该从后往前看,我们定义dp[i]为从i往1开始,每四个一组第一个产生贡献的

异或前缀和,明显这个dp[i]是可以线性搞定的,

那么就分类寻找递推关系:

4n长度肯定是0,

4n+1长度是dp[r]^dp[l-4](注意利用首尾一致这样的特点),

4n+2长度是dp[r]^dp[l-3]^dp[r-1]^dp[l-4],

4n+3长度是dp[r-1]^dp[l-3].

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt      
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e5+100;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定一个序列,层层定义三个函数,
定义都是数学式子很复杂,但是终归就是
每一位的数取还是不取的关系.

题目分析:
第一层:1,1,1,1,1
第二层:1,0,1,0,1,事实上就是上一层前缀和模2,
第三层:1,1,0,0,1,1,0,0,...
到这里即可,
那么分析,对于(l,r)这样的查询区间,
每个数其确定是否贡献的函数,比如如果区间长度是4吧:
1 4
2 3
3 2
4 1
可以知道这四对数没有一对产生贡献,
可以推广到4n长度,与此同时那么4n+1,4n+2,4n+3也可以推断,
分别把右边序列向下偏移一位,
贡献状态分别是:
每四个取第一个数,每四个取第一二个数,每四个取第二个数.
刚开始我还在想着从前往后,但这个序列贡献有点小小的对称思想,
应该从后往前看,我们定义dp[i]为从i往1开始,每四个一组第一个产生贡献的
异或前缀和,明显这个dp[i]是可以线性搞定的,
那么就分类寻找递推关系:
4n长度肯定是0,
4n+1长度是dp[r]^dp[l-4](注意利用首尾一致这样的特点),
4n+2长度是dp[r]^dp[l-3]^dp[r-1]^dp[l-4],
4n+3长度是dp[r-1]^dp[l-3].
*/
int n,a[maxn];
int solve(int l,int r){
    int ans=0,flag=(r-l+1)%4;
    if(flag==0) return 0;
    else if(flag==1){
        ans=a[r];
        if(l>=4) ans^=a[l-4];
    }else if(flag==2){
        ans=a[r]^a[r-1];
        if(l>=3) ans^=a[l-3];
        if(l>=4) ans^=a[l-4];
    }else{
        ans=a[r-1];
        if(l>=3) ans^=a[l-3];
    }
    return ans;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        rep(i,1,n+1) scanf("%d",&a[i]);
        rep(i,4,n+1) a[i]^=a[i-4];
        int q;scanf("%d",&q);
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",solve(x,y));
        }
    }
    return 0;
}

 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值