连续异或的结果

题目

https://codeforces.com/contest/2225/problem/D
大概意思就是,给你一段数字,要求你选取的这段数字里必须包含x,且这段数字的异或和是0

核心原理

image
所以题目就变成了,求这段数字中有多少个0x-1中有多少数字对4取模是1,xn中有多少数字对4取模是1,然后前面的数字*后面的数字就是总共有多少种,后面求模完之后是0的也是这样的

代码

#include<bits/stdc++.h>
using namespace std;
const long long MOD=998244353;
long long count0(long long a, long long b){
    if(a>b) return 0;
    long long res=0;
    if(a==0){res++; a=1;}
    if(a>b) return res;
    long long first=a+((3-a%4)+4)%4;//寻找第一个对4取模之后答案是3的数字
    if(first<=b) res+=(b-first)/4+1;//然后看在这个区间里有多少个数字也满足对4取模之后答案是3,用等差数列的方法
    return res%MOD;
}
long long count1(long long a, long long b){
    if(a>b) return 0;
    long long first=a+((1-a%4)+4)%4;
    if(first<=b) return ((b-first)/4+1)%MOD;
    return 0;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        long long n,x;
        scanf("%lld %lld",&n,&x);
        //你可能会问,不是从1开始的吗?怎么变成了从0开始的,
        //假设我们求出了 k和j是对4取模之后余数为1/0的两个点,那么这段区间的异或和就是f[j]^f[k-1]
        //从0开始不会影响异或的结果的,因为多异或一个0不会影响结果的,从0开始就是为了让1~n都有机会当左端点,不然的话,假设x=1
        //那么就变成count(1,0),那就直接是0了,因为直接return 0嘛,但是事实不是0,这个显而易见的,第二个例子就是x=1的啊
        //而且上面的例子给的也是从0开始的

        //其实这个就是一个结论,直接记住就好了
        long long A0=count0(0,x-1);
        long long B0=count0(x,n);
        long long A1=count1(0,x-1);
        long long B1=count1(x,n);
        printf("%lld\n",(A0*B0+A1*B1)%MOD);
    }
}
posted @ 2026-04-23 20:28  Time_q  阅读(8)  评论(0)    收藏  举报