1.与运算
(点我)
这个题的大概意思:给
2
2
2个数
n
n
n和
x
x
x,其中满足
n
&
(
n
+
1
)
&
(
n
+
2
)
&
(
n
+
3
)
.
.
.
&
m
=
x
n\&(n+1)\&(n+2)\&(n+3)...\&m=x
n&(n+1)&(n+2)&(n+3)...&m=x,求最小的
m
m
m,只要满足
m
>
=
x
m>=x
m>=x即可
这个题在二进制的角度来看就是假设
n
n
n的位是
100101
那么 x x x一定是从某一位开始与 n n n不同,并且不同的这一位(记为 q q q位)一定是 x x x为 0 0 0, n n n为 1 1 1;并且从这一位往右 x x x的位都是 0 0 0.只有这样才是满足条件的,假设不是这样。
- 情况一: x x x的 q q q位是为 1 1 1, n n n的为 0 0 0:一定不可能。与运算不可能弄出来一个 1 1 1
- 情况2: x x x从 q q q位往右还有 1 1 1:一定不可能。既然 x x x是累积与运算的结果,那么与到 q q q位一定是用一个 \space q + 1 q+1 q+1位(向左数1位)为 1 1 1后面都是 0 0 0的数 \space 与出来的。
综上所述, x x x的位可以是:
100100
在这里有一个
t
r
i
c
k
trick
trick:
n
n
n的
q
+
1
q+1
q+1位为
1
1
1.这个
q
+
1
q+1
q+1位(向左数1位)为
1
1
1后面都是
0
0
0的数 应该与
n
n
n中
q
+
1
q+1
q+1位(含)相加(造出
m
m
m),但是如果
n
n
n的
q
+
1
q+1
q+1位为
1
1
1,那么
q
+
1
q+1
q+1位就会被消掉了。比如说
n
=
3
n=3
n=3和
x
=
2
x=2
x=2最后求出来
m
m
m是
4
4
4,结果是错的。证明略去。
代码:
#include<iostream>
#include<cstdio>
#include<bitset>
typedef long long ll;
using namespace std;
typedef long long ll;
int main(void)
{
int t;
scanf_s("%d", &t);
for (int i = 0; i < t; i++)
{
ll n, x;
scanf_s("%lld%lld", &n, &x);
bitset<100> n2;
bitset<100> x2;
n2 = n;
x2 = x;
int flag = 1;
for (int i = 99; i >= 0; i--)
{
if (x2[i] != n2[i]&&x2[i]==1&&n2[i]==0)
{
flag = 0;
break;
}
else if (x2[i] != n2[i])
{
if (x2[i + 1] == 1)
{
flag = 0;
break;
}
for (int j = i - 1; j >= 0; j--)
{
if (x2[j] != 0)
{
flag = 0;
break;
}
}
if (flag == 0)
break;
x2[i + 1] = 1;
break;
}
}
if (flag == 0)
printf("-1\n");
else
{
ll sum = 0;
for (int i = 99; i >= 0; i--)
{
sum = sum * 2 + x2[i];
}
printf("%lld\n", sum);
}
}
}
2.或运算
集合?(点我)
这个题的大概意思是给
n
n
n个数,然后每个数是以位的形式给出的,比如说第
i
i
i个数有
3
3
3位:
2
,
3
,
5
2,3,5
2,3,5(
2
,
3
,
5
2,3,5
2,3,5位上是
1
1
1)那么第
i
i
i行的样例就会给出:
3 2 3 5
现在要找出两个子序列,让他们的或运算的结果相等。
我一开始想到集合上去了,就是把每个数的位加入到集合里面,然后看集合大小有没有变化,这个和加入顺序有很大关系,并且在某种程度是错误的:
比如说:
3 1 3 4
3 2 3 1
3 3 5 2
这个样例其实是正确的,但是每次加入集合都有新元素,所以算法不对。实际上只要记录下来所有数的位的出现次数,然后再看是否存在一个数的所有位出现次数
>
1
>1
>1即可。
数据结构:我之前交了个代码超时了,不是很理解 (用的
v
e
c
t
o
r
vector
vector,所以统计次数的那个位置使用了
m
a
p
map
map
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
//const int length = 2e5 + 5;
int main(void)
{
int t;
scanf_s("%d", &t);
for (int i = 0; i < t; i++)
{
int n;
scanf_s("%d", &n);
vector<vector<int>> edge(n);
// vector<int> c(length, 0);
map<int, int> c;
for (int i = 0; i < n; i++)
{
int k;
scanf_s("%d", &k);
for (int j = 0; j< k; j++)
{
int a;
scanf_s("%d", &a);
edge[i].push_back(a);
c[a]++;
}
}
int flag = 0;
for (int i = 0; i < n; i++)
{
int yh = 1;
//for (int j = 0; j < edge[i].size(); j++)
for(int j:edge[i])
{
if (c[j] == 1)
{
yh = 0;
break;
}
}
if (yh == 1)
{
flag = 1;
break;
}
}
if (flag)
printf("YES\n");
else
printf("NO\n");
}
}
比较:
1840
m
s
1840ms
1840ms是使用局部数组,在循环里用
m
e
m
s
e
t
memset
memset
1855
m
s
1855ms
1855ms那个用的全局数组,然后在循环里用
m
e
m
s
e
t
memset
memset
超时的是把二维数组移到全局,然后在循环里声明一个
v
e
c
t
o
r
vector
vector
93
m
s
93ms
93ms是在循环里用
m
a
p
map
map
可能是开一个
v
e
c
t
o
r
vector
vector比较花时间,本来就是险过,但是用
m
a
p
map
map就很快…