题解 | #小 Q 与异或#
小 Q 与异或
https://ac.nowcoder.com/acm/contest/11171/A
题解 小 Q 与异或
牛客练习赛? DIV1!
给你异或方程组的一些方程解,要求构造出异或方程组的全部解
性质一:
如果有两个方程右端点相同而解值不相同,则方程组不存在解
性质二:异或的逆元为其本身
利用性质二可通过x^y=z ->x^y^y逆=z^y逆 -> x=z^y逆 ->x=z^y解逆元方程
情况一:区间右端点相等但x值不相等 输出-1
情况二:异或逆元为0才能使异或方程成立 违反题目要求 输出-1
但情况二除非给你两组右端点差值为1且x值相同,否者是必定能构造出来的,因为x的范围为1e9,而答案数组的范围为2e10,所以在没有区间约束的情况下可以使用2^31和2^30左右横跳,无论给你什么x值因为小于目前的异或和,所以必定不会使异或逆元为0,即必定是存在解的
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int N=1e6+5;
struct node
{
int r;
int val;
}e[1000005];
struct cmp
{
bool operator()(const node&t1,const node&t2)
{
if(t1.r!=t2.r)
return t1.r<t2.r;
return t1.val<t2.val;
}
};
long long ans[1000005];
int main()
{
long long che=pow(2,31);
int n,m,flag=0,count=1;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&e[i].r,&e[i].val);
}
sort(e,e+m,cmp());//先排个序,按递增右端点性质通过递推处理区间
int old=0,arr=0,old2=0;
long long bas;long long s=0;//bas 当前异或方程的解 s 异或方程的总异或和
for(int i=1;i<e[0].r;i++)//处理前边界
{
bas=che;
ans[arr++]=che;
s^=che;
old=i;
old2=bas;
if(count==1)//左右横跳填充
{
count=0;
che/=2;
}
else {
count=1;
che*=2;
}
}
for(int i=0;i<m;i++)
{
int t=e[i].r;
if(t==old&&old2==e[i].val)
continue;
else if(t==old&&old2!=e[i].val)
{
flag=1;
break;
}
if(arr==0)
{
s=bas=ans[arr++]=e[i].val;
if(bas==0)//处理第一位为0的情况
{
flag=1;
break;
}
}
else {
if(t-old>1)//左右横跳填充区间缝隙
{
for(int j=0;j<t-old-1;j++)
{
bas=che;
s^=bas;
ans[arr++]=che;
if(count==1)
{
count=0;
che/=2;
}
else {
count=1;
che*=2;
}
// printf("%lld\n",bas);
}
bas=s^e[i].val;
s=e[i].val;
if(bas==0)
{
flag=1;
break;
}
ans[arr++]=bas;
}
else {
bas=s^e[i].val;
s=e[i].val;
if(bas==0)
{
flag=1;
break;
}
ans[arr++]=bas;
}
}
// printf("%lld\n",bas);
old2=e[i].val;
old=e[i].r;
}
if(flag==1)
{
printf("-1\n");
return 0;
}
for(int i=0;i<arr;i++)
{
printf("%lld ",ans[i]);
}
for(int i=arr;i<n;i++) //左右横跳填充右区间
{
printf("%lld ",che);
if(count==1)
{
count=0;
che/=2;
}
else {
count=1;
che*=2;
}
}
printf("\n");
}
/*
5 4
1 5
2 4
3 15
4 62
5 3
1 2
2 6
2 4
5 3
3 4
3 4
4 6
6 3
5 4
5 4
5 4
6 1
3 0
*/
迅雷公司福利 193人发布
