OR
题目:
示例1
输入
4
7 5 5
7 9 5
输出
2
大致题意:给出b,c数组的2–n位置上的数据,构造a数组使得:
(
2
≤
i
≤
n
)
(2 \leq i \leq n)
(2≤i≤n)
b
i
=
a
i
−
1
or
a
i
,
c
i
=
a
i
−
1
+
a
i
b_i = a_{i-1} \text{or} \, a_{i} , c_i = a_{i-1} + a_{i}
bi=ai−1orai,ci=ai−1+ai成立
问可以构造几个满足条件的a数组。
样例中的两个a数组分别为 2 , 5 , 4 , 1 2,5,4,1 2,5,4,1 和 3 , 4 , 5 , 0 3,4,5,0 3,4,5,0
分析:
1.位运算、二进制:
在二进制中有这样一个公式:
a
+
b
=
a
and
b
+
a
or
b
a+b=a \text{and}\,b +a\text{or}\,b
a+b=aandb+aorb
由于加法中包含进位,而二进制的and和or运算中不需要考虑进位问题,所以我们可以通过
(
2
≤
i
≤
n
)
(2 \leq i \leq n)
(2≤i≤n)
c
i
=
c
i
−
b
i
c_{i}=c_{i}-b_{i}
ci=ci−bi的操作使得题目中a数组与c数组的关系转变为
c
i
=
a
i
−
1
and
a
i
c_i = a_{i-1} \text{and}\, a_{i}
ci=ai−1andai
2. a a a数组的关联:
在我们模拟样例的时候可以发现一旦确定了
a
1
a_1
a1的值,
a
i
a_i
ai
(
2
≤
i
≤
n
)
(2 \leq i \leq n)
(2≤i≤n)的值也有唯一性,
a
i
a_i
ai
(
2
≤
i
≤
n
)
(2 \leq i \leq n)
(2≤i≤n)只有两种情况:
1.一个定值
2.没有数值可以满足(即a数组构造失败)
通过这个规律我们可以将题目转换为求有多少种满足条件的
a
1
a_1
a1
但该如何去寻找
a
1
a_1
a1的个数呢?
此时我们可以借助二进制:
从低位(
2
0
2^0
20)到高位(
2
30
2^{30}
230)每一位都查找一遍康康此位满足条件的有2种(0和1均可)还是1种(0或1)还是无论取0还是1都没办法满足(此时可以直接得到0的答案。即
a
1
a_1
a1无论如何取值都不能满足题目的要求)
1. b i b_i bi和 c i c_i ci二进制之间的一些关系:
以下数据都是用二进制形式表示:
当只看此条件我们以为只看b和c同位置上的1/0就可以判断a在此位置上的取值可能性那就错了
错代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=4933;
int b[N],c[N];
int main()
{
int n;
cin>>n;
for(int i=2;i<=n;i++)cin>>b[i];
for(int i=2;i<=n;i++){
cin>>c[i];
c[i]-=b[i];
}
int ans=1;
for(int i=0;i<31;i++){//枚举a[1]的每一位
int flag=2;//初始为2种情况(0,1)均可
for(int j=2;j<=n;j++){
int bn=b[j]>>i&1;//取b[j]第i位
int cn=c[j]>>i&1;//取c[j]第i位
if(bn==cn&&flag==2)flag=1;
else if(bn==0&&cn==1){
flag=0;
break;
}
}
ans=ans*flag;
}
cout<<ans<<endl;
return 0;
}
错误原因:没有考虑 a i − 1 a_{i-1} ai−1与 a i a_{i} ai之间的关联
2. a i − 1 a_{i-1} ai−1与 a i a_{i} ai之间的关联:
即当情况为1时(只能取1或0)的时候考虑少了点:
解决方法:
当判断
a
1
a_{1}
a1在此位置上只有一种取值之后用fron来记录
a
i
−
1
a_{i-1}
ai−1的值,在遍历
b
j
b_j
bj和
c
j
c_j
cj第i位上的值的过程中进行fron的更新就好啦!
ac代码:(写的有点长不过懂就好hh)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=4933;
int b[N],c[N];
int main()
{
int n;
cin>>n;
for(int i=2;i<=n;i++)cin>>b[i];
for(int i=2;i<=n;i++){
cin>>c[i];
c[i]-=b[i];
}
int ans=1;
for(int i=0;i<31;i++){//枚举a[1]的每一位
int flag=2,fron=-1;//初始为2种情况(0,1)均可
for(int j=2;j<=n;j++){
int bn=b[j]>>i&1;//取b[j]第i位
int cn=c[j]>>i&1;//取c[j]第i位
if(bn==cn&&flag==2){
flag=1;
if(bn==0)fron=0;//记录此时a[j]取值
else fron=1;
}
else if(bn&&cn==0&&flag==1){
if(fron==0)fron=1;//更新a[j]取值
else fron=0;
}
else if(bn==cn&&flag==1){
if((bn==0&&fron==1)||(bn==1&&fron==0)){
cout<<"0"<<endl;
return 0;
}
//更新a[j]取值
if(bn==0)fron=0;
else fron=1;
}
else if(bn==0&&cn){
cout<<"0"<<endl;
return 0;
}
}
ans=ans*flag;
}
cout<<ans<<endl;
return 0;
}