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;
}