【题解】QDUOJ.94.ltwy的比特绷板键盘

题目:
https://qduoj.com/problem/94/

主要考察模拟2进制的置位和复位,其中有些细节需要注意:

  1. i的范围是[1,32768],也就是说输出结果的范围是[0, 2^32767], 所以只用一个整型变量存储是不行的,要用数组模拟大数。
  2. 对于”调皮的操作”,需要考虑的全面一些,诸如:

pRint
printf
set 1 1
reset 1i
print 0

都是被当作”调皮的操作”.

主要思路:
预处理,保存2的0~32767次方的值,共32768个值,每个值最多不超过10000位,使用unsigned long long int存储只需要不多于555(粗略)位,sizeof(unsigned long long int) * 555 * 32768未超出要求内存。

记录所有二进制位的情况,要求输出的结果为所有二进制为1的位对应预处理的值的和。

可能有大量print操作,所以计算实时进行,每次set或reset都对结果进行计算。

特别注意处理”调皮的操作”

实现:

//#define gets(buf) gets_s(buf,101)
#include <stdio.h>
#include <string.h>

#define MAX 32768
#define LEN 555

typedef unsigned long long int ull;
ull bits[MAX / sizeof(ull) + 1];//当前值的二进制位记录
ull x[LEN];//当前值
ull z[MAX + 1][LEN] = { 1 };//z[i]为2的i次方
ull Z = 1e18;

void addto(ull * a, ull * b) {
    //将a加上b
    for (int i = 0; i < LEN; i++) {
        a[i] += b[i];
        if (a[i] > Z) {
            a[i + 1] += a[i] / Z;
            a[i] -= Z;
        }
    }
}
void subto(ull * a, ull * b) {
    //将a减去b
    for (int i = 0; i < LEN; i++) {
        if (a[i] < b[i]) {
            a[i] += Z;
            a[i + 1] -= 1;
        }
        a[i] -= b[i];
    }
}
void print(ull * x) {
    //输出当前值
    for (int j = LEN - 1; j >= 0; j--) {
        if (x[j]) {
            printf("%llu", x[j]);
            for (int k = j - 1; k >= 0; k--)
                printf("%018llu", x[k]);
            puts("");
            return;
        }
    }
    puts("0");
}
void init() {
    //预处理计算2的0~32767次方
    for (int i = 1; i <= MAX; i++) {
        addto(z[i], z[i - 1]);
        addto(z[i], z[i - 1]);
    }
}
int main(void) {
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int i, k, n, m, flag;
    char s[4][103], s1[103];
    init();
    for (; ~scanf("%d\n", &n);) {
        memset(bits, 0, sizeof(bits));
        memset(x, 0, sizeof(x));
        *x = *bits = n;
        scanf("%d\n", &m);
        for (; m--;) {
            gets(s[0]);
            /////////////////处理调皮操作////////////////
            i = *s[3] = *s[2] = 0;
            sscanf(s[0], "%s%s%s", s[1], s[2], s[3]);
            if (strcmp(s[1], "print"))
                for (; s[2][i]; i++)
                    if (s[2][i] > '9' || s[2][i] < '0')
                        break;
            if (s[2][i] || *s[3] || (strcmp(s[1], "set") && strcmp(s[1], "reset") && strcmp(s[1], "print")) || (strcmp(s[1], "print") && !*s[2])) {
                m++;
                puts("Lei shen bie nao, me me da~");
                continue;
            }
            ///////////////////////////////////////////
            if (*s[0] == 'p') print(x);//输出结果
            else {
                sscanf(s[2], "%d", &k);
                k--;

                flag = bits[k / sizeof(ull)] & (1 << k % sizeof(ull));
                //flag记录目标位的情况
                if (*s[0] == 's') {
                    bits[k / sizeof(ull)] |= (1 << k % sizeof(ull));//目标位置1
                    if (!flag) addto(x, z[k]);//如果目标位当前为0,则重新计算结果
                }
                else if (*s[0] == 'r') {
                    bits[k / sizeof(ull)] &= ~(1 << k % sizeof(ull));//目标位置0
                    if (flag) subto(x, z[k]);//如果目标位当前为1,则重新计算结果
                }
            }

        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c_duoduo/article/details/52201055
94