2021牛客多校第八场补题 D-OR

链接: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−1​orai​, 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
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
typedef pair 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<>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]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<

你可能感兴趣的:(算法)