11.5

    一、比较简单的一道模拟题。对于两个数,他们有一个and值,一个or值,一个xor值。现在这三个值给你任意几个,让你求这两个数可能的方案数(注意:1,2和2,1是相同的方案),如果互相冲突就输出0,如果无穷解就输出inf,否则输出方案数。很容易发现这是一个枚举所有情况的模拟题,总共七种情况,一次判断是否冲突,是否无穷解,或者有解的个数。

    无解的情况:(二进制下某一位)or为0,xor为1;xor为1,and为1;or为0,and为1

    无穷解:只有一个xor、只有一个and

    其他的都是有限解,就一次判断情况枚举就好了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,ans_and,ans_or,ans_xor;
ll ans;
int main(){
	freopen("bit.in","r",stdin);
	freopen("bit.out","w",stdout);
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&ans_and,&ans_or,&ans_xor);
		if(ans_or==-1&&ans_xor==-1){
			printf("inf\n");
		}else if(ans_and==-1&&ans_xor==-1){
			ans=1;
			for(;ans_or;ans_or>>=1){
				if(ans_or&1) ans*=3;
			}
			printf("%lld\n",ans);
		}else if(ans_and==-1&&ans_or==-1){
			printf("inf\n");
		}else if(ans_xor==-1){
			ans=1;bool flag=0;
			for(int i=0;i<=31;i++){
				if(ans_and&(1<<i)){
					if(ans_or&(1<<i)) ans*=1;
					else flag=1;
				}
				else{
					if(ans_or&(1<<i)) ans*=2;
					else ans*=1;
				}
			}
			if(flag) printf("0\n");
			else printf("%lld\n",ans);
		}else if(ans_and==-1){
			ans=1;bool flag=0;
			for(int i=0;i<=31;i++){
				if(ans_or&(1<<i)){
					if(ans_xor&(1<<i)) ans*=2;
					else ans*=1;
				}
				else{
					if(ans_xor&(1<<i)) flag=1;
					else ans*=1;
				}
			}
			if(flag) printf("0\n");
			else printf("%lld\n",ans);
		}else if(ans_or==-1){
			bool flag=0;ans=1;
			for(int i=0;i<=31;i++){
				if(ans_and&(1<<i)){
					if(ans_xor&(1<<i)) flag=1;
				}else{
					if(ans_xor&(1<<i)) ans*=2;
				}
			}
			if(flag) printf("0\n");
			else printf("%lld\n",ans); 
		}else{
			ans=1;bool flag=0;
			for(int i=0;i<=31;i++){
				if(ans_and&(1<<i)){
					if(ans_or&(1<<i)) ans*=1;
					else flag=1;
				}
				else{
					if(ans_or&(1<<i)) ans*=2;
					else ans*=1;
				}
			}
			for(int i=0;i<=31;i++){
				if(ans_and&(1<<i)){
					if(ans_xor&(1<<i)) flag=1;
				}
			}
			for(int i=0;i<=31;i++){
				if(ans_or&(1<<i)==0){
					if(ans_xor&(1<<i)) flag=1;
				}
			}
			if(flag) printf("0\n");
			else printf("%lld\n",ans);
		}
	}
	return 0;
}

   二、一道比较复杂的数组模拟题,简单来说就是你用一个数组维护一个集合A,然后判断集合中哪些数存在,你需要用桶维护,桶原来使用的bool数组你需要改成int,因为你的标记应该是一个时间戳。如果合并,就扫描B的所有数有没有在集合A中,没有就添加进数组里。如果是交集,先把A集合数组清零,仍然是扫描B,如果A中也有就加入新的集合。因为SUM B是3e6的,所以你复杂度O(SUM)完全可以过。当然中间还穿插有区间加和区间减,你只需要做一个懒标记就好了。我当时只拿了90,因为有一个区间加减的情况我还是去扫描A了所以复杂度不确定。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
char xch,xB[1<<15],*xS=xB,*xTT=xB; 
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++) 
inline int read() {  
	int x=0,f=1;char ch=getc();
	while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getc();}  
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}  
	return x*f; 
} 
const int N=3e6+10;
const int M=1e6;
int m,a[N],b[N],f[N],top,past,de,siz;
ll sum;
int main(){
	freopen("jihe.in","r",stdin);
	freopen("jihe.out","w",stdout);
	m=read();
	past=1;
	for(int i=1;i<=m;++i){
		int op=read();
		if(op==3){
			sum+=top;++de;
			printf("%lld\n",sum);
		}else if(op==4){
			sum-=top;--de;
			printf("%lld\n",sum);
		}else if(op==1){
			for(int j=1;j<=top;++j){
				f[a[j]+M]=0;
			}
			for(int j=1;j<=top;++j){
				f[a[j]+de+M]=past;
				a[j]=a[j]+de;
			}
			de=0;
			siz=read();
			for(int j=1;j<=siz;++j){
				b[j]=read();
				if(f[b[j]+M]!=past) a[++top]=b[j],f[b[j]+M]=past,sum+=b[j];
			}
			printf("%lld\n",sum);
		}else if(op==2){
			//for(int j=1;j<=top;++j) cout<<a[j]<<' ';
			//cout<<endl;
			for(int j=1;j<=top;++j){
				f[a[j]+M]=0;
			}
			for(int j=1;j<=top;++j){
				f[a[j]+de+M]=past;
			}
			de=0;
			siz=read();top=0;sum=0;
			for(int j=1;j<=siz;++j){
				b[j]=read();
				if(f[b[j]+M]==past) 
					a[++top]=b[j],f[b[j]+M]=i,sum+=b[j];
			}
			past=i;
			printf("%lld\n",sum);
		}
	}
	return 0;
}

第三题是一道容斥题,目前只会写70分的。把方块的四周都当成空地,如果没有空地,把相邻的两个相同方块的缝隙也当成空地。对所有的极大空地联通块儿编号,然后给方块标记。一个方块儿最多被四种编号的空地打标记,然后我们把每一种方块儿放到一个队列里,发现所有与某几种编号相邻的方块的个数可以做一个sum,然后从左往右扫一遍,做个容斥就好了。这中间记录前缀和会用到map,所以复杂度是N*M*15*logN。100分的并过不了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值