省选校内模拟D10

T1

  • 给出一个序列,你需要支持修改一个数以及查询是否存在一个数x使得所有数异或上x后按从小到大排列,有则输出最小的
  • n,m≤10^6,所有数字不超过2^30

Solution

  • 考虑相邻两个数第一个不相同的二进制位
  • 这些不同的二进制位唯一确定了x的取值,如果没有冲突就合法

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=1e6+10;
int num[35][2],pos[N],a[N],n,m,x,y;
int get(int now,int i){ return (a[now]>>i)&1; }
void work(int now){
	per(i,30,0){
		if(get(now,i)!=get(now-1,i)){
			pos[now]=i;break;
		}
	}
	if(pos[now]>=0)num[pos[now]][get(now,pos[now])<get(now-1,pos[now])]++;
}
void del(int now){
	if(pos[now]>=0)num[pos[now]][get(now,pos[now])<get(now-1,pos[now])]--;
	pos[now]=-1;
}
void getans(){
	int ans=0;
	per(i,30,0){
		if(num[i][1]&&num[i][0]){puts("-1");return;}
		if(num[i][1])ans|=1<<i;
	}
	printf("%d\n",ans);
}
int main()
{
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	memset(pos,-1,sizeof(pos));
	scanf("%d",&n);
	rep(i,1,n)scanf("%d",&a[i]);
	scanf("%d",&m);
	rep(i,2,n)work(i);
	getans();
	while(m--){
		scanf("%d%d",&x,&y);
		if(x>1)del(x);if(x<n)del(x+1);
		a[x]=y;
		if(x>1)work(x);if(x<n)work(x+1);
		getans();
	}return 0;
}

T2

  • 首先考虑40分做法
  • 考虑连续的一段后缀,当这段M个数大于F个数时,就要把M向前提
  • ans=max(ans,M-F-1)
  • 至于为什么-1,是因为可以少提一个M,因为最后一定会剩下一个F,FM组合即可
  • 100分模拟40分的计算流程,发现有些步骤可以省略直接算出答案
#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
#define ll long long
using namespace std;
const ll N=1e5+10;
ll n,m,x,a[N],tot=0,ans=0,now=0,maxn=0,sum=0;
string s[N];
int main()
{
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	scanf("%lld",&n);
	scanf("%lld",&m);
	rep(i,1,m)cin>>s[i]>>a[i];
	per(i,m,1){
		now=maxn=0;
		per(j,s[i].size()-1,0){
			if(s[i][j]=='M')++now;
			else --now;
			maxn=max(maxn,now);
		}
		if(now>0)ans=max(ans,sum+now*(a[i]-1)+maxn-1);
		else ans=max(ans,sum+maxn-1);
		sum+=now*a[i];
	}
	if(sum>0)puts("-1");
	else cout<<ans;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值