4616. 【NOI2016模拟7.12】二进制的世界

2 篇文章 0 订阅
1 篇文章 0 订阅

Description

Input

Output

Sample Input

5 and 1
3 5 2 7 1

Sample Output

1 1
2 1
5 1
1 3

Data Constraint

Solution

  • 一道看起来很神仙的题目,实际上运用了平衡规划的神奇技巧。
  • 让我们先来看一看暴力。
  • 我们设 fi 表示 a=i 时的答案。
  • 每一次加入一个数都可以跟任意一个i进行运算更新fi
  • 这样我们能做到 O(216) 修改, O(1) 查询。

  • 接下来我们引入平衡规划的思想。对于每加入一个数,我们都要分别对其做以上的操作,我们能不能平衡一下,变成 O(28) 修改, O(28) 查询呢?
  • 实际上这就是这题的突破口。
  • 又因为这是二进制运算,我们不难想到将其拆成两半,一半长度是28,将待查询的数称作A,以加入的数称作B,设 f[s1][s2] 表示A的前半段为s1,B的后半段为s2,A与B前半段运算的最大值。
  • 这个状态十分神奇。
  • 因为我们可以发现,查询的时候只需要枚举B的后半段,s1 确定,用最大值 f[s1][s2] ,和A的后半段与B的后半段运算的结果相加即可得到答案。 O(28) 枚举。
  • 而更新f的时候,s2 确定,枚举s1 更新即可, O(28) 。
  • 所以我们就可做到 O(n*28) 的时间复杂度。
  • 这是我除了分块以外的第一道平衡规划的题目,十分神奇,这类的题目比较少见,还需要好好掌握。

Code 

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof a)
#define N 100004
using namespace std;
I n,opt,tp,now,x,y,mx,tot,f[260][260],g[260][260],S=255;
char c;
void R(I &x){
	x=0;char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
}
I w(I x,I y){
	if(opt==1) return x&y;
	else if(opt==2) return x|y;
	return x^y; 
}
I main(){
	freopen("binary.in","r",stdin);
	freopen("binary.out","w",stdout);
	R(n);
	c=getchar();
	while(c<'a'||c>'z') c=getchar();
	opt=(c=='a')?1:(c=='o'?2:3);
	R(tp);
	F(i,0,S){
		F(j,0,S) f[i][j]=-0x7fffffff;
	}
	F(k,1,n){
		R(x);
		y=x&S;x>>=8;
		mx=-1;
		F(i,0,S){
			now=f[x][i]+w(i,y);
			if(now>mx){mx=now;tot=0;}
			if(now==mx) tot+=g[x][i];
		}
		F(i,0,S){
			now=w(i,x)<<8;
			if(f[i][y]<now) f[i][y]=now,g[i][y]=0;
			if(f[i][y]==now) g[i][y]++;
		}
		if(k>1){
			printf("%d",mx);
			if(tp) printf(" %d",tot);
			printf("\n");
		}
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值