题解:AtCoder Beginner Contest 261 E - Many Operations(难度:普及+/提高)
- 题目
链接:E - Many Operations (atcoder.jp)
- 思路
蒟蒻的我看到这道题都不想做了……(普及组实力小孩)
言归正传,让我们看一下思路:假设我们将要做1、2、3、……、i-2、i-1、i号操作,我们可以用f[x][0]表示如果开始做这些操作时c的二进制倒数第x位为0,操作后c的二进制倒数第x位是多少;f[x][1]表示如果开始做这些操作时c的二进制倒数第x位为1,操作后c的二进制倒数第x位是多少。这样,我们有效的避免了每组操作都要以O(n)的代价做一遍(如果这样最终复杂度为O(n2))。
实现:我们用二维数组ans[33][2]实现f数组记录每次操作后的结果,为了方便,我们一开始就把c转化成数组形式,即数组的第i项存储它二进制中倒数第i为,这个数组就是now。之后循环遍历每次操作,同时更新ans。有点小难度的是把now转化成正常数输出,这个大家待会看代码。
- 代码
链接:Submission #42245709 - AtCoder Beginner Contest 261
#include<bits/stdc++.h>
using namespace std;
int ans[33][2]={},now[33]={},c=0,n=0;
int main(){
scanf("%d%d",&n,&c);
int t=c;
for(int i=1;i<=30;i++){
if(t%2==1){
now[i]=1;
}else{
now[i]=0;
}
t/=2;
ans[i][0]=0;
ans[i][1]=1;
}
//把ans初始化,并把c变成now
for(int i=1;i<=n;i++){
int opt=0;
scanf("%d",&opt);
if(opt==1){
//and
int num=0;
scanf("%d",&num);
int t=num;
for(int j=1;j<=30;j++){
if(t%2==1){
ans[j][0]&=1;
ans[j][1]&=1;
}else{
ans[j][0]&=0;
ans[j][1]&=0;
}
t/=2;
}
//用num的每一位二进制更新答案
}
if(opt==2){
//or
int num=0;
scanf("%d",&num);
int t=num;
for(int j=1;j<=30;j++){
if(t%2==1){
ans[j][0]|=1;
ans[j][1]|=1;
}else{
ans[j][0]|=0;
ans[j][1]|=0;
}
t/=2;
}
//用num的每一位二进制更新答案
}
if(opt==3){
//xor
int num=0;
scanf("%d",&num);
int t=num;
for(int j=1;j<=30;j++){
if(t%2==1){
ans[j][0]^=1;
ans[j][1]^=1;
}else{
ans[j][0]^=0;
ans[j][1]^=0;
}
t/=2;
}
//用num的每一位二进制更新答案
}
int s=0;
for(int j=30;j>=1;j--){
if(now[j]==0){
now[j]=ans[j][0];
}else{
now[j]=ans[j][1];
}
if(now[j]==1){
s++;
}
s*=2;
}
//把now用ans更新,并转换成int类型整数输出
printf("%d\n",s/2);
//注意最后一步s不用乘二
}
return 0;
}