题解:P17766 「LDOI R2」位运算 / Bit
这是啥?青吗?
首先显然拆位考虑。
判断无解
以下情况很显然无解:
接下来枚举位,假设
-
若
a=1 :- 若
b=0 ,显然不会有n 个数字出现与结果为1 ,或结果为0 的情况,直接输出-1 。 - 若
c\ne n\bmod 2 ,由于全部数这一位都要为1 ,那么c 理论应该与n\bmod 2 相等,此时我们应该判掉。
- 若
-
若
b=0 :- 若
c=1 :b=0 时所有这一位都是0 ,因此不可能出现c=1 。判掉。
- 若
记录每一位有多少个 1
很显然,这些数的总和越大,这些数的积的最大值就越大。因此我们考虑让一位上尽可能多的数为
我们考虑分讨:
-
若
a=1 ,那么这一位有n 个1 。 -
若
b=0 ,那么这一位有0 个1 。 -
若
c=1 :- 若
n 为奇数,那么最多有n-2 个1 。这里要把n=1 判掉。 - 若
n 为偶数,那么最多有n-1 个1 。
- 若
-
若
c=0 :- 若
n 为偶数,那么最多有n-2 个1 。 - 若
n 为奇数,那么最多有n-1 个1 。
- 若
贪心求积的最大值
学过高中数学必修一的同学一定知道这个不等式:
事实上,对
考虑如何证明它:
::::success[证明]
设
由高中数学选择性必修
所以有:
所以
::::
而该不等式取等的条件是
所以我们按位从高到低贪心,假设这一位有
但是我们发现
设极大值
按位从高到低贪心,先把所有数都赋值为极大值,假设这一位有
阈值 120
但是显然
我们考虑当
- 我们选出来前
k 大,显然因为n 足够大,所以全是极大值。 - 我们把这些极大值的第
i 位扣掉。 - 因为第
i 位被设置为0 了,所以它不再是极大值,不可能再次把它的一位设置为0 。
也就是说我们构造出的数列每一个数都是
由于最多有
那么上面情况的
复杂度
实测
::::success[Code]
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define i128 __int128
#define Nos puts("-1");return;
ll n,x,y,z;
const int N=61,mod=998244853;
int a[N],b[N],c[N],d[N];
int f[N];
ll p[10005],tmp[135];
priority_queue<ll>q;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
typedef unsigned long long ull;
char buf[1<<20],*p1,*p2;
char gc() {
if(p1==p2) p2=(p1=buf)+fread(buf,1,1<<20,stdin);
return *p1++;
}
ull rd() {
ull s=0;
char c=gc();
while(c<48) c=gc();
while(c>47) s=s*10+(c^48), c=gc();
return s;
}
void solve(){
n=rd();x=rd();y=rd();z=rd();
if(n==1&&x!=y){
puts("-1");return;
}
for(ll i=0;i<=59;i++){
a[i]=((x>>i)&1);
b[i]=((y>>i)&1);
c[i]=((z>>i)&1);
}
ll ans=0;
memset(d,0,sizeof d);
for(int i=0;i<=59;i++){
if(a[i]==1){
if(c[i]!=(n&1)){
puts("-1");return;
}
if(b[i]==0){
puts("-1");return;
}
d[i]=n;
continue;
}
if(b[i]==0){
if(c[i]==1){
puts("-1");return;
}
d[i]=0;
if(a[i]==1){
puts("-1");
return;
}
continue;
}
if(a[i]==1||b[i]==0)continue;
if(c[i]==1){
if(n&1){
if(n<=1){
puts("-1");return;
}
d[i]=n-2;
}
else {
d[i]=n-1;
}
}
else{
if((n+1)&1){
if(n<=1){
puts("-1");return;
}
d[i]=n-2;
}
else {
d[i]=n-1;
}
}
}
int r=0;
ll t=0;
for(int i=0;i<=59;i++){
if(d[i]!=0){
if(d[i]!=n)f[i]=n-d[i];
else f[i]=-1;
t+=(1ll<<i);
}
else{
f[i]=-1;
}
if(f[i]!=-1)r+=f[i];
}
if(n>=120){
ll suu=1;
for(int i=0;i<=59;i++){
if(f[i]!=-1){
if(f[i]==1)suu=suu*((t-(1ll<<i))%mod)%mod;
else if(f[i]==2){
suu=suu*((t-(1ll<<i))%mod)%mod;
suu=suu*((t-(1ll<<i))%mod)%mod;
}
}
}
suu=suu*qpow(t%mod,n-r)%mod;
printf("%lld\n",suu);
return;
}
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)q.push(t);
int leN=0;
for(int i=59;i>=0;i--){
int t=0;
leN=0;
if(f[i]==-1)continue;
while(!q.empty()){
t++;
tmp[++leN]=q.top();
q.pop();
if(t==f[i])break;
}
for(int j=1;j<=leN;j++){
tmp[j]-=(1ll<<i);
q.push(tmp[j]);
}
}
ll sum=1;
int len=0;
while(!q.empty()){
p[++len]=q.top();
sum*=(p[len]%mod);sum%=mod;
q.pop();
}
ll uu=(1ll<<60)-1,vv=0,ww=0;
for(int i=1;i<=n;i++){
uu=uu&p[i];vv=vv|p[i];ww=ww^p[i];
}
if(uu!=x||vv!=y||ww!=z){
puts("-1");return;
}
printf("%lld\n",sum);
}
int main(){
int T;T=rd();
while(T--)solve();
}
::::