Codeforces Round #626 D. Present 异或按位确定 +二分or双指针

Codeforces Round #626 D. Present 异或按位确定 +二分or双指针

题意

给n个数,求他们两两的和的异或结果 n(4e5) 值域(1e7)

思路

异或问题一般都是按位确定,那么怎么确定第k位的值呢。首先第k位的值只和[1,k]位有关系,也就是说只跟a[i]本来在这一位有的数和进位有关系。那么怎么处理和的问题呢。首先我们只考虑[1..k]位,那么他们的和记为sum,如果sum在第k位有值 那么sum的值为 \(2^k+x\)因为只考虑[1..k]位所以a的最大值为\(2^{k+1}-1\) sum的最大值也就是\(2^{k+2}-2\)所以我们可以得到当\([2^k,2^{k+1}-1]\)以及[2^{k+1}+2^{k}-1,2^{k+2}-2]如果sum落在这两个区间上,那么它的第k位就是1的。我们要算的是有几对和是位于这两个范围内的,很显然,我们可以先对a数组mod\(2^{k+1}\)排序后利用二分找范围。这样复杂度就是0(nlognlogc)同样的 因为满足单调性,也可以运用双指针这样就少了一个log变成O(nlogc)

二分

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define F first
#define S second
#define mkp make_pair
#define pii pair<int,int>
typedef long long ll;
#define int ll
const int inf=0x3f3f3f3f;
const int maxn=4e5+5;
const int mod= 998244353;
int b[maxn],a[maxn];
int n;
int solve(int x,int y,int z){

        if(y<x)return 0;
        int l=lower_bound(b+1,b+1+n,x)-b;
        int r=upper_bound(b+1,b+1+n,y)-b;
            //cout<<x<<" fuck"<<y<<" "<<(n-l+1)-(n-r+1)<<endl;
        int flag=0;
        if(z>=x&&z<=y)flag=1;
        return (n-l+1)-(n-r+1)-flag;
}
int32_t main(){
    scanf("%lld",&n);
    int up=0;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),up=max(up,a[i]);
    int ans=0;

    for(int k=1;k<=2e7;k<<=1){
        for(int j=1;j<=n;j++)b[j]=a[j]%(k*2ll);
        sort(b+1,b+1+n);
        int sum=0;
        for(int j=1;j<=n;j++){
        //  cout<<solve((1<<(k-1))-b[j],(1<<k)-b[j]-1)<<" "<<solve((1<<(k-1))+(1<<(k))-b[j],(1<<(k+1))-2-b[j]);
            //cout<<endl;
        //  cout<<j<<" "<<((1<<(k-1))-b[j])<<" "<<((1<<k)-b[j]-1)<<" "<<solve((1<<(k-1))-b[j],(1<<k)-b[j]-1)<<endl;
            //cout<<j<<" "<<((1<<(k-1))+(1<<(k))-b[j])<<" "<<((1<<(k+1))-2-b[j])<<" "<<solve((1<<(k-1))+(1<<(k))-b[j],(1<<(k+1))-2-b[j])<<endl;
            sum+=solve(k-b[j],2ll*k-b[j]-1,b[j]);
            sum+=solve(2ll*k+k-b[j],k*4ll-2-b[j],b[j]);
        }
        sum/=2;
    //  cout<<sum<<endl;
        if(sum&1)ans^=(k);
    }
    printf("%lld\n",ans);
    return 0;
}

双指针

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define F first
#define S second
#define mkp make_pair
#define pii pair<int,int>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=4e5+5;
const int mod= 998244353;
int b[maxn],a[maxn];
int n;

int main(){
    scanf("%d",&n);
    int up=0;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),up=max(up,a[i]);
    int ans=0;
    for(int k=1;k<=2e7;k<<=1){
        for(int j=1;j<=n;j++)b[j]=a[j]%(k*2ll);
        sort(b+1,b+1+n);
        long long  sum=0;
        int p1=1,p2=1,p3=1;
        for(int j=n;j>=1;j--){
            while(p1<=n&&b[p1]+b[j]<k)p1++;
            while(p2<=n&&b[p2]+b[j]<k+k)p2++;
            while(p3<=n&&b[p3]+b[j]<k+k+k)p3++;
            sum+=max(0,min(j,p2)-p1);
            sum+=max(0,j-p3);
        }
        if(sum&1)ans^=(k);
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/ttttttttrx/p/12444098.html

时间: 2024-10-29 02:41:33

Codeforces Round #626 D. Present 异或按位确定 +二分or双指针的相关文章

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序 题意 有 a[ i ] 个数 要求选最多的数 使其和不超过 S ,且在此情况下,和最小选最多数情况下 和最小 且 每个数有加成 如果选了 k个数 那么加成后 就是 a[ i ] + k*i ; 题解 二分mid 表示选了个数 加成一下,将加成以后结果排序一下 , 若前 mid数 和大于 s 则此方案不可行 PS 要用 long long ..... 还有 co

Codeforces.835E.The penguin&#39;s game(交互 按位统计 二分)

题目链接 \(Description\) 有一个长为\(n\)的序列,其中有两个元素为\(y\),其余全为\(x\).你可以进行\(19\)次询问,每次询问你给出一个下标集合,交互库会返回这些元素的异或和.给定\(n,x,y\),你需要求出两个\(y\)的下标. \(n\leq 1000,1\leq x,y\leq 10^9\). \(Solution\) 对连续区间询问得到的结果只有那么几种,可以直接判断\(y\)的个数的奇偶性.但是区分不出来该区间有0个还是2个\(y\). 两个\(y\)的

Codeforces Round #626 Div2 D. Present(位掩码,二分)

题目链接:https://codeforces.com/contest/1323/problem/D 题意:给了大小为4e5的数组a,其中1<=ai<=1e7.求所有点对和的异或和,即: 思路: 按位来考虑,因为两个元素的和<=2e7,而2e7小于225,因此结果最多是25位.我们考虑答案中每一位ans[k]的值(0<=k<=24). 显然,ai中仅有0-k位会对第k位有影响,因此对数组a全部对2k+1取模,得到数组b,对b按升序排序. 这样,0<=bi<=2k+

Codeforces Round #626 (Div. 2) B. Count Subrectangles

题目连接:https://codeforces.com/contest/1323/problem/B 题意:给一个大小为n的a数组,一个大小为m的b数组,c数组是二维数组c[i][j]=a[i]*b[j],问面积为k的矩形有几个. 题解:先把k的所有因子存入一个数组里,然后遍历因子,表示在a数组有 i 个连续的1,那么如果在b数组里有 k/i 个连续的1,形成的矩形面积就是k(自己脑补一下吧),计算出a数组中符合条件的个数乘以b数组中符合条件的个数,然后把每个因子下的都加起来就是答案. 1 #i

Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)【ABCD】(题解)

目录 涵盖知识点:思维.树状数组. 比赛链接:传送门 A - Even Subset Sum Problem B - Count Subrectangles C - Unusual Competitions D - Present E - Instant Noodles F - Reality Show 涵盖知识点:思维.树状数组. 比赛链接:传送门 A - Even Subset Sum Problem 题意: 找一个子序列使得和为偶数 题解: 选一个偶数或者两个奇数. Accept Code

Codeforces Round #628 (Div. 2)(异或,构造思维)

题意:给出u,v.要求给出一个最短的数组,要求这个数组异或结果为u,和为v.   解析 :所谓xor,相同为0,否则为1.就是一个不进位的二进制加法(这里不理解的建议去看看二进制加法法则,再与此做对比). 1:u>v.根据上述,不进位的u都比v大,那进位的话会更大,这些数加起来肯定比v大,所以无解,-1. 2:u==v,直接输出u即可    3:u<v.我们可以从结果为3个 数入手.可以构造为x,x,u.为什么,因为x^x==0,而0异或一个数等于这个数的本身,即x^x^u==u.要想保证和为

Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)

A. Even Subset Sum Problem 题意:找和是偶数的子集,没什么好说的,直接上代码. #include <iostream> #include <algorithm> using namespace std; int n,x; int a[110]; int main() { int t; scanf("%d",&t); while(t--) { x=0; scanf("%d",&n); for(int i

Codeforces Round #626 (Div. 1, based on Moscow Open Olympiad in Informatics)B(位运算,二分查找)

从低到高枚举当前位i,把所有数字对1<<(i+1)取模,因为比i位高的数字不会影响到低位,在这些数中,两两组成一对,每对的和如果在第i位上为1,++计数,如果计数为奇数,则答案上这一位为1.这个组对的过程通过排序后二分查找完成. 1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 int a[400007]; 5 int b[400007]; 6 int main(){

Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)(A-C)

题意:根据第一段,只是让你找到任意一组元素,和为偶数即可.还可以根据OUTPUT最后一句,多种答案,输出任意一种.    解析:随便找嘛,所以如果碰到单个偶数,直接输出,否则找出任意两个奇数输出即可.都没有,就输出-1. #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> using namespace std; typedef l