题解:P13995 【MX-X19-T4】「FeOI Round 4.5」Supernova

· · 题解

不难发现第 2 次操作至多进行 1 次,因为在进行了

然后我们考虑 $1$ 操作的本质:考虑其补集,进行一次 $1$ 操作相当于枚举子集,因此我们只要算出来 $x$ 和 $y$ 补集在 $p$ 补集的子集中的顺序然后相减再加 $1$ 就可以了,而计算顺序也很简单,对二进制拆分后的每个 $2^n$ 找一下子集中比自己小的数然后加起来就可以。时间复杂度 $O(T\log n)$。(还有就是,这题怎么评上蓝的?) ```cpp #include<bits/stdc++.h> #define int long long #define mp make_pair #define fi first #define se second #define lb lower_bound #define fr front() #define pii pair<int,int> #define INF (1ull<<63)-1 #define bp __builtin_popcountll using namespace std; int t,x,y,p,maxn=INF; signed main(){ ios::sync_with_stdio(false); cin>>t; while(t--){ cin>>x>>y>>p; if(x==y){ cout<<0<<"\n";continue; } if((x|(p+1))==y||((x+1)|p)==y){ cout<<1<<"\n";continue; } int num=1,nxt=(x|(p+1)); if(nxt>((x+1)|p)&&(nxt&p)==p&&nxt<=y)x=nxt; else x=(x+1)|p; if(x==y){ cout<<1<<"\n";continue; } if(y<x||(y&p)!=p){ cout<<-1<<"\n";continue; } int nx=(maxn^x),ny=(maxn^y);p=(maxn^p); int ax=0,ay=0; for(int i=0;i<=62;i++){ if(nx&(1ll<<i)){ int k=((1ull<<i)-1)&p; ax+=(1ull<<bp(k)); //cout<<k<<" "<<bp(k)<<" "<<ax<<"\n"; } } for(int i=0;i<=62;i++){ if(ny&(1ll<<i)){ int k=((1ull<<i)-1)&p; ay+=(1ull<<bp(k)); //cout<<k<<" "<<ay<<"\n"; } } //cout<<ax<<" "<<ay<<" "; cout<<ax-ay+1ll<<"\n"; } }