题面
题目描述
小Z最近学会了二进制数,他觉得太小的二进制数太没意思,于是他想对一个巨大二进制数做以下 4 种基础运算:
运算 1:将整个二进制数加 1
运算 2:将整个二进制数减 1
运算 3:将整个二进制数乘 2
运算 4:将整个二进制数整除 2
小Z很想知道运算后的结果,他只好向你求助。
(Ps:为了简化问题,数据保证+,-操作不会导致最高位的进位与退位)
输入输出格式
输入格式:
第一行两个正整数 n,m,表示原二进制数的长度以及运算数。
接下来一行 n 个字符,分别为‘0’或‘1’表示这个二进制数。
第三行 m 个字符,分别为‘+’,‘-’,‘*’,‘/’,对应运算 1,2,3,4。
输出格式:
一行若干个字符,表示经过运算后的二进制数。
输入输出样例
输入样例#1:
4 10 1101 */-*-*-/*/
输出样例#1:
10110
说明
【数据规模和约定】
对于 30%的数据,1 ≤ n,m ≤ 1000。
对于 60%的数据,1 ≤ n,m ≤ 10^5。
对于 100%的数据,1 ≤ n,m ≤ 5*10^6。
【时空限制】
2s/128M
分析
首先看一下数据,n和m最多可以到5000000。
这说明什么呢,就是我们要用些比较玄学的做法了...
我们知道,n/2=n>>1,n*2=n<<1。
那我们的乘除运算就可以再优化一点了。
然而,如果直接右移或左移一位的话,效率就是O(n),太慢...
于是我想出了一个比较好的方法,就是栈模拟(?)...
右移一位,相当于把最低位去掉,也就是出栈(pop);
左移一位,相当于末尾加一个0,也就是入栈(push)一个0。
这样一来,我们就能把乘除运算优化到O(1)了。
加法的话,我们可以一直从最低位往最高位访问,不停地改变,如果是0就跳出循环。
例如n=1101011,加法运算后是n=1101100,我们只要访问到百位就可以了。
减法同理。
这样一来,加法和减法的最差效率是O(n),乘除的最差效率是O(1),应该没问题。
提交了也AC了。
程序
#include <cstdio> using namespace std; bool bin[10000005]; int end=-1; int main(){ int i, j; int n, m; char ch; scanf("%d %d ", &n, &m); for(i=1; i<=n; i++){ end++; bin[end]=getchar()&1; } scanf(" "); for(i=1; i<=m; i++){ ch=getchar(); if(ch==‘+‘){ j=end; while(bin[j]){ bin[j]=0; j--; } bin[j]=1; } else if(ch==‘-‘){ j=end; while(!bin[j]){ bin[j]=1; j--; } bin[j]=0; } else if(ch==‘*‘) end++; else{ bin[end]=0; end--; } } for(i=0; i<=end; i++) putchar(bin[i]+48); return 0; }