数学、位运算、贪心、二分、交互

利用性质!利用性质!利用性质!利用性质!利用性质!利用性质!利用性质!

令答案为 $a,b,c$,钦定 $a < b < c$,根据 $a \operatorname{xor} b \operatorname{xor} c$ 的结果分讨。

  • $a \operatorname{xor} b \operatorname{xor} c \neq 0$

由于 $a \neq b \neq c$,如果值域前缀 $[1,i]$ 中有至少一个数被拿走,这个前缀的异或和就非 $0$,可以二分得到 $a$ 的值。同理二分值域后缀 $[a+1,n]$ 得到 $c$ 的值,然后询问一次全局异或和得到 $a \operatorname{xor} b \operatorname{xor} c$ 的值,利用 $a,c$ 计算出 $b$。

  • $a \operatorname{xor} b \operatorname{xor} c = 0$

看题解来的,无从下手。

由于 $a,b,c$ 的异或和为 $0$,如果 $a$ 的第 $k$ 个二进制位为 $1$,$b,c$ 中必定有且仅有一个数的第 $k$ 个二进制位为 $1$。该性质对 $b,c$ 同样有效。

又因为 $a < b < c$ 所以 $b,c$ 的最高二进制位相同,并且 $a$ 的这个二进制位为 $0$。

枚举 $a$ 的最高二进制位,设其为第 $i$ 个二进制位,找到最小的使得值域前缀 $[1,2^{i+1} - 1]$ 中的数异或和非 $0$ 的整数 $i$,这个非 $0$ 异或和即为 $a$ 的值。得到 $a$ 之后在区间 $[a+1,n]$ 二分出 $c$。注意可能不存在异或和为 $0$ 的值域前后缀,所以应当初始化 $a=1,c=n$

时间复杂度 $O(\log n)$。

#include<bits/stdc++.h>
using namespace std;
long long n,a,c,sum;
long long ask(long long l,long long r){
    static long long ret;
    cout<<"xor"<<' '<<l<<' '<<r<<endl;
    cin>>ret;
    return ret;
}
void solution(){
    cin>>n,a=1ll,c=n,sum=ask(1,n);
    if(sum!=0){
        long long l=1ll,r=n;
        while(l<=r){
            long long mid=(l+r)>>1;
            if(ask(1ll,mid)) r=mid-1;
            else a=mid+1,l=mid+1;
        }
    }
    else{
        for(int i=0;i<=60;i++){
            a=ask(1ll,(1ll<<(i+1))-1);
            if(a!=0ll) break;
        }
    }
    long long l=a+1,r=n;
    while(l<=r){
        long long mid=(l+r)>>1;
        if(ask(mid,n)) l=mid+1;
        else c=mid-1,r=mid-1;
    }
    cout<<"ans"<<' '<<a<<' '<<(sum^a^c)<<' '<<c<<endl;
}
int T;
int main(){
    ios::sync_with_stdio(0);
    cin>>T;
    while(T--) solution();
    return 0;
}
最后修改:2024 年 11 月 11 日
如果觉得我的文章对你有用,请随意赞赏