今天刷题时遇到一个题,本以为是暴力+大模拟,结果看完别人的AC代码后人都傻了,竟然是位运算。其中用到了异或
^
这种运算符。
先上原题连接 :传送门
题目意思很好理解,有无限多个路灯,编号为1.2.3…刚开始时都是关着的,每次对一盏灯的操作都会改变它的状态(即开变成关,关变成开)。每次操作会给你一个实数a和一个整数b,一次操作是一次从1到b的k次循环,编号为a*k的实数部分的灯会改变状态。问,最后剩下的灯的编号为多少。
这是个很简单的模拟+暴力题,因为数据保证不超过2e6,所以我也用暴力的方法AC了
AC代码
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <queue>
using namespace std;
int ans;
int tong[2000005];
int main()
{
int n;
double a, b;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a >> b;
for (int j = 1; j <= b; j++)
tong[(int)(a * j)] = (tong[(int)(a * j)] + 1) % 2;
}
for (int i = 1; i <= 2000005; i++)
if (tong[i])
{
printf("%d\n", i);
break;
}
return 0;
}
接下来介绍主角——按位异或运算(^
)
先介绍一下异或运算(^
)的概念和用法
按位异或运算将两个运算分量的对应位按位遵照以下规则进行计算:
0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0
即相应位的值相同的,结果为 0,不相同的结果为 1。
例如,2^6结果为4
因为2表示为二进制为0010,6表示为二进制为0110
两数只有第三位相异,因此最后的结果为0100,即为4
了解了异或运算的用法,我们接下来可以看题了。
首先我们要清楚,任意一个数a异或同一个数两次后值依旧为a,比如7^3
,结果为4,4^3
后,结果为仍然为7,这刚好与灯的两种状态对应,即对一盏灯做偶数次操作,该灯状态不变。
最后,该题保证n次操作完后只有一盏灯亮,其实这是这题能使用异或运算的先决条件。因为这样就说明虽然有很多操作,但是两两抵消之后,只剩下一个操作,该操作对应的编号^0之后的值还是该灯的编号。也就是最后唯一开着的那盏灯。
AC代码
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <queue>
using namespace std;
int ans;
int main()
{
int n;
double a, b;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a >> b;
for (double j = 1; j <= b; j++)
ans ^= (int)(j * a);//异或运算
}
cout << ans << endl;
return 0;
}