链接:https://ac.nowcoder.com/acm/contest/11259/D
来源:牛客网
题目描述
There are two sequences of length n−1n-1n−1, b=(b2,b3,…,bn)b=(b_2,b_3,\ldots,b_n)b=(b2,b3,…,bn), c=(c2,c3,…,cn)c=(c_2,c_3,\ldots,c_n)c=(c2,c3,…,cn). Here, each bib_ibi,cic_ici is a non-negative integer.
Now, the sequence a=(a1,a2,…,an)a=(a_1,a_2,\ldots,a_n)a=(a1,a2,…,an) considers beautiful if and only if forall iii (2≤i≤n)(2 \leq i \leq n)(2≤i≤n), bi=ai−1 or aib_i = a_{i-1} \, \text{or} \, a_{i}bi=ai−1orai, ci=ai−1+aic_i = a_{i-1} + a_{i}ci=ai−1+ai and each aia_iai is a non-negative integer.
Now, Toilet-Ares asks you to calculate the number of beautiful sequences.
输入描述:
The first line contains one integer nnn (2≤n≤105)(2 \leq n \leq 10^5)(2≤n≤105) - the length of sequence aaa. The second line contains n−1n-1n−1 integers b2,b3,…,bnb_2,b_3,\ldots,b_nb2,b3,…,bn (0≤bi<230)(0 \leq b_i < 2^{30})(0≤bi<230) - the elements of sequence bbb. The third line contains n−1n-1n−1 integers c2,c3,…,cnc_2,c_3,\ldots,c_nc2,c3,…,cn (0≤ci<231)(0 \leq c_i < 2^{31})(0≤ci<231) - the elements of sequence ccc.
输出描述:
Print one number - the number of beautiful sequences.
题目大意
给你一个n和两个数组b和c
你需要输出数组a的种类个数 其中a[i]+a[i+1]=c[i+1], a[i]ora[i+1]=b[i+1]
题目思路
首先需要知道这样一个性质:
x+y=x|y+x&y
那么c[i] = a[i]+a[i-1] = a[i] | a[i-1] +a[i] & a[i-1]=b[i] + a[i] & a[i-1]
c[i] - b[i]=a[i] & a[i-1];①
b[i] =a[i] | a[i-1] ; ②
由①可知每个c[i] 必须大于b[i],否则直接输出ans=0
由题意可知当确定a【1】时整个a序列都会被确定
那么我们可以枚举a1然后去判断该a1能否符合题意 若符合ans++
这样的时间复杂度是 O(2^31*n)明显不行
那么我们考虑另外一种更优的计算方式
容易发现对于如果每一位分别单独进行计算
假设当前是k位
在一开始由①②两个式子确定a1在k位的可能值 然后进行逐位进行更新ai和ai+1 判断是否可行
如果第k位a[1] | a[2]=1 而且a[1] & a[2] =0 那么意味这a1在第k位有两种选择情况 否则只有一种选择
在k位时若有x种情况最终可行 就让ans*=x
如果有0种可行 则直接输出ans=0
代码注释得很清楚
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
typedef pair<int, int> PII;
int n,b[maxn];
int c[maxn];
int a[maxn];
int flag=1;
int nd[maxn];
int sol(int a1,int a2,int i)
{
int time=1;
for(int j=2;j<=n;j++)//先判断第一种情况
{
int annow=((c[j]-b[j])>>(i-1))&1;//计算出a[j-1] & a[j] 在第i位的01情况
int ornow=((b[j])>>(i-1))&1;// 计算出a[j-1] | a[j] 在第i位的01情况
if(int(a1&a2)!=annow||int(a1|a2)!=ornow)//不符合情况
{
time--;
break;
}
if(j==n)continue;
int annex=((c[j+1]-b[j+1])>>(i-1))&1;//计算出a[j+1] & a[j] 在第i位的01情况
int ornex=((b[j+1])>>(i-1))&1;// 计算出a[j+1] | a[j] 在第i位的01情况
if(annex)//该位and是1
{
if(ornex)
{
if(a2==1)a1=a2,a2=1;//如果下一个&和|都是1说明 a[j+1] a[j]都得是1
else //如果a[j]已经不是1了 说明不符合题意
{
time--;
break;
}
}
else //如果下一个 &是1 |是0 不符合题意
{
time--;
break;
}
}
else
{
if(ornex)//如果下一个&是0 |是1 说明 a[j+1] a[j]有一个是1 看当前a【j】的情况
{
if(a2==1)a1=a2,a2=0;
else a1=0,a2=1;
}
else //如果下一个&和|都是0说明 a[j+1] a[j]都得是0
{
if(a2==1)
{
time--;
break;
}
else a1=a2=0;
}
}
}
//cout<<time<<endl;
return time;
}
int main()
{
cin>>n;
for(int i=2;i<=n;i++)
{
scanf("%d",&b[i]);
}
for(int i=2;i<=n;i++)
{
scanf("%d",&c[i]);
if(c[i]<b[i])//如果ci小于bi则a[i] & a[i-1<0不符合题意
{
flag=0;
}
}
if(flag==0)
{
cout<<0<<endl;
return 0;
}
int t;
t=c[2]-b[2];
int tt=t;
int cnta=0;
while(tt>0)
{
a[++cnta]=tt%2;//求出a[1] & a[2] 每一位的01情况
tt/=2;
}
int delta=b[2];
int cntd=0;
while(delta>0)
{
cntd++;
if(delta%2&&a[cntd]==0)//出a[1] | a[2] 每一位的01情况
nd[cntd]=1;
delta/=2;
}
ll ans=1;
for(int i=1;i<=cntd;i++)//一共有cntd位
{
if(nd[i]==1)//如果该位 a[1] & a[2] =0但是a[1] | a[2] =1 a1两种情况
{
int time=0;//a1就有两种情况
time+=sol(1,0,i);
time+=sol(0,1,i);
if(time==0){flag=0;break;}
else ans*=time;
}
else
{
int a1,a2;
if((int)((c[2]-b[2])>>(i-1))&1)//如果i位 a[1] & a[2] =1
{
if(a[i]==1)
{
a1=1;
a2=1;
}
else
{
flag=0;
break;
}
}
else if((int)((b[2])>>(i-1))&1)//如果i位 a[1] | a[2] =1
{
if(a[i]==1)a1=1,a2=0;
else a1=0,a2=1;
}
else a1=0,a2=0;
int time=0;
time+=sol(a1,a2,i);
if(time==0){
flag=0;break;
}
else ans*=time;
}
}
if(flag==0)cout<<0<<endl;
else
{
cout<<ans<<endl;
}
return 0;
}