首页 > 代码库 > [hihoCoder]1509_异或排序

[hihoCoder]1509_异或排序

链接:https://hihocoder.com/problemset/problem/1509

题意:异或排序

给定一个序列a[],给定一个函数 f(i) = a[i] XOR S, S为常数

问有多少个 0 <= S < 2^60 使得函数 f 为单调不减函数

(既然是中文题估计都能看得懂)

 


 

题解:

水题 ( 啪 x ) 

由于每一个数都有一个二进制表示,由数论知识我们知道比较两个数是从高位开始比较的,当比较到某一位发现一个数该位为1而另一个数该位为0时就知道前面那个数一定比后面那个要大,而再考虑异或的性质:

0 Xor 1 = 1

1 XOR 1 = 0

0 XOR 0 = 1

假设我们有两个数x,y,不妨设x>y,那么存在第i位使得x与y在更高的位都相等但是x在该位为1而y在该位为0,由于 1 XOR 1 = 0, 0 XOR 1 = 1,那么假若存在S,只要S在第i位为1,就能使得 (x XOR S) <= (y XOR S)

反正只要该位符合题意就好,其他位是任意的,显然这个任意的数目就是我们要求的了0。0思路大体也出来的

先生成一个S[60]的数组,扫描一遍,检索两个数是小大还是大小关系,小大关系的话在那个位置0,大小关系的话在那个位置成1,注意如果那位本来有数的话要看看是否一致,不一致说明这个东西他不存在

最后看看有多少个位置是没有被固定的,那么2的那个那个数目次方就是所求。

#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
#include<iostream>
#include<string>
#include<sstream>
//stringstream ss(line)
#include<algorithm>
//sort(a,a+n,cmp)
//p=lower_bound(a,a+n,x)-a+1(大于或等于x的第一个位置)
#include<vector>
#include<bitset>
//bitset<N> xx

using namespace std;

typedef long long ll;

const int MAXN = 55;
const int MAXL = 65;

ll pow_[MAXL];
int im[MAXL];
ll num[MAXN];

ll quickPow(int k){
	if(pow_[k]!=0)	return pow_[k];
	else return pow_[k] = quickPow(k/2)*quickPow(k-k/2);
}

int findHi(ll x){
	int i;
	for(i=60 - 1;i>=0;i--){
		if(x>=quickPow(i))	break;
	}
	return i;
}

int main(){
	memset(pow_,0,sizeof(pow_));
	pow_[0]=1,pow_[1]=2;
	quickPow(60);
	memset(im,-1,sizeof(im));
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)	scanf("%lld",num+i);
	ll temp;
	int flag=-1;
	for(int i=1;i<n;i++){
		temp = num[i-1]^num[i];
		flag=(num[i-1]>num[i]);
		int ans = findHi(temp);
		if(ans==-1)	continue;
		if(im[ans]==-1)	im[ans]=flag;
		else if(im[ans]!=flag){
			printf("0");
			return 0;
		}
	}
	int sum=0;
	for(int i=0;i<60;i++){
		//printf("%d",im[i]);
		if(im[i]==-1)	sum++;
	}
	printf("%lld",quickPow(sum));
	return 0;
}

  

[hihoCoder]1509_异或排序