NC18979 毒瘤xor
题目链接
关键点:
1、首先看懂题目:该题是给出一个数组,给出数组区间,求一个数x与该区间所有的数进行异或,之后所求出的最大值,那么最好情况是每一位的异或都为1
2、因为异或运算位与位之间互不影响,所以我们可以一位一位的考虑,如果在一个区间里的所有数,某个位的1多,那么就异或0(1^0=1, 0^0=0),同理,如果0多,就异或1
3、那么我们就要求出每一位的01数量,想到前缀和,sum[i][j]数组表示第前i个数字的第j位的1的数量,在输入数组的时候,就开始处理前缀和。
4、处理前缀和时要注意
sum[i][j] = sum[i-1][j];
if ((a[i]>>j)&1==1)
sum[i][j]++;
5、最后根据输入的区间,算出区间里的某位1的数量,如果1的数量小于区间里的数的一半,那么答案就在该位取1
完整代码:
# include <iostream>
# include <algorithm>
# include <cstdio>
using namespace std;
int n;
int a[100000+10];
int sum[100000+10][40];
int main()
{
scanf("%d", &n);
for (int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
for (int j=0; j<31; j++)
{
sum[i][j] = sum[i-1][j];
if ((a[i]>>j)&1==1)
sum[i][j]++;
}
}
int x;
scanf("%d", &x);
for (int i=1; i<=x; i++)
{
int t, w, ans=0;
scanf("%d%d", &t, &w);
int total=0;
for (int j=0; j<31; j++)
{
total = sum[w][j]-sum[t-1][j];
if (total*2<w-t+1)
ans |= (1<<j);
}
printf("%d\n", ans);
}
return 0;
}
NC20860 兔子的区间密码
题目链接
关键点:
1、题目大意为,给出一个区间,求该区间里的两个数异或的最大值
2、每一位进行异或所得出的值最好要为1,那么我们发现在一个区间的两个端点上,从最高位开始往后的位上,如果位上数字相同,那么取的两个数也只能取相同,因此异或出来就为0,
如果不同,那么就可以一个取1,一个取0(该位上),之后所有位取1的后面就可以全为0,取0的后面就全为1,这样不仅保证了数字在区间内,还保证了尽量多的可以异或为1,因此我们可以
找出端点两个数从最大位到最小位的(二进制),第一个不同的数,从这个位置开始(包括)全为1到结尾
3、由于题目给出区间数字过大,答案和区间要开long long
完整代码
# include <cstdio>
# include <iostream>
using namespace std;
typedef long long ll;
int n;
int main()
{
scanf("%d", &n);
for (int i=1; i<=n; i++)
{
ll l, r;
scanf("%lld%lld", &l, &r);
ll pos=-1, x=1;
for (int j=63; j>=0; j--)
{
int a = (l>>j)&1;
int b = (r>>j)&1;
// cout<<"a"<<a<<" "<<"b"<<b<<" "<<endl;
if (a!=b)
{
pos = j;
break;
}
}
cout<<(x<<(pos+1))-1<<endl;
}
return 0;
}
NC17857 起床困难综合症
题目链接
关键点:
1、大致题意为,给出一个值,在经过若干计算后,要使该值最大
2、同样的,因为&,|,^,这些位运算只与当前位有关,因此我们可以只考虑当前位,求可以得到的最大攻击值
3、并且每一位我们可以取0或者1,那么我们可以将所有的位都为0和1,去试一下经过所有运算后的结果,该位为0的结果为1,那么答案的该位就为1(因为初始值是从0-m,所以这样取不会超过该范围),如果不为1,那么看一下1的结果是否为1,如果为1那么还得在保证在范围内,才能取1
4、最后一点,我们将所有位用0和1去尝试,可以转换成用0(天然的所有位为0)和-1(所有位为1)去直接进行运算即可
完整代码
# include <cstdio>
# include <iostream>
using namespace std;
int n, m;
int main()
{
scanf("%d%d", &n, &m);
int a = 0, b=-1, pos=0;
// while (m)
// {
// b|=(1>>pos);
// m/=2;
// }
for (int i=1; i<=n; i++)
{
string s;
int x;
cin>>s>>x;
if (s=="AND")
{
a&=x;
b&=x;
}
else if (s=="OR")
{
a|=x;
b|=x;
}
else
{
a^=x;
b^=x;
}
}
int x=0;
for (int i=0; i<31; i++)
{
if ((a>>i)&1)
{
x|=(1<<i);
}
else
{
if (((b>>i)&1)&&((1<<i)<=m))
{
x|=(1<<i);
m-=(1<<i);
}
}
}
printf("%d", x);
return 0;
}