• AcWing 4604. 集合询问


    有一个整数集合,初始时集合为空。

    现在,要对该集合进行 tt 次操作,操作分为以下三种:

    • + x,将一个非负整数 xx 添加至集合中。注意,集合中可以存在多个相同的整数。
    • - x,从集合中删除一个非负整数 xx。可以保证执行此操作时,集合中至少存在一个 xx。
    • ? s,询问操作,给定一个由 00 和 11 组成的模板 ss,请你计算并输出此时集合中有多少个元素可以与 ss 相匹配。

    关于判断整数 xx 与模板 ss 是否匹配的具体方法如下:

    • 首先,在进行匹配判断前,应保证 xx 与 ss 位数相同,如果两者位数不同,则位数更少的一方需补充前导 00 至与位数更多的一方位数相同为止。
    • 从最高位开始,对每一位进行逐个判断,如果 ss 的第 ii 位为 00,则 xx 的第 ii 位必须为偶数,如果 ss 的第 ii 位为 11,则 xx 的第 ii 位必须为奇数。
    • 如果有任意一位不满足上述条件,则视为 xx 与 ss 不匹配。如果所有位均满足上述条件,则视为 xx 与 ss 匹配。

    例如,如果 s=010s=010,则 92、2212、50、41492、2212、50、414 与 ss 匹配,而 3、110、25、10303、110、25、1030 与 ss 不匹配。

    输入格式

    第一行包含整数 tt,表示操作次数。

    接下来 tt 行,每行包含一个操作,格式如题面描述。

    保证至少存在一个查询操作。

    输出格式

    每个查询操作输出一行结果,一个整数,表示集合中与 ss 匹配的元素个数。

    数据范围

    前 44 个测试点满足 1≤t≤201≤t≤20。
    所有测试点满足 1≤t≤1051≤t≤105,0≤x<10180≤x<1018,ss 的长度范围 [1,18][1,18]。

    输入样例1:

    1. 12
    2. + 1
    3. + 241
    4. ? 1
    5. + 361
    6. - 241
    7. ? 0101
    8. + 101
    9. ? 101
    10. - 101
    11. ? 101
    12. + 4000
    13. ? 0

    输出样例1:

    1. 2
    2. 1
    3. 2
    4. 1
    5. 1

    输入样例2:

    1. 5
    2. + 200
    3. + 200
    4. ? 0
    5. - 200
    6. ? 0

    输出样例2:

    1. 2
    2. 1

    思路: 所有的数最大18位,所以可以分为2^18种可能(每一位数都是偶数或者奇数,最长18位)。

    可以用字典树写,也可以用一种神奇的写法。

    字典树写法:

    1. #include<iostream>
    2. using namespace std;
    3. typedef long long LL;
    4. const int N = 3e6 + 10;
    5. int q[N];
    6. void add(LL x)
    7. {
    8. LL res=1;
    9. for(int i=1;i<=18;i++)
    10. {
    11. int y=x%10;
    12. x/=10;
    13. if(y%2) res=res*2+1;
    14. else res*=2;
    15. }
    16. q[res]++;
    17. }
    18. void sub(LL x)
    19. {
    20. LL res=1;
    21. for(int i=1;i<=18;i++)
    22. {
    23. int y=x%10;
    24. x/=10;
    25. if(y%2) res=res*2+1;
    26. else res*=2;
    27. }
    28. q[res]--;
    29. }
    30. int query(LL x)
    31. {
    32. int res=1;
    33. for(int i=1;i<=18;i++)
    34. {
    35. int y=x%10;
    36. x/=10;
    37. if(y%2) res=res*2+1;
    38. else res*=2;
    39. }
    40. return q[res];
    41. }
    42. int main()
    43. {
    44. int n;
    45. cin>>n;
    46. char op[2];
    47. LL x;
    48. while(n--)
    49. {
    50. scanf("%s%lld",op,&x);
    51. if(*op=='+') add(x);
    52. else if(*op=='-') sub(x);
    53. else printf("%d\n",query(x));
    54. }
    55. return 0;
    56. }

    神奇的写法:

    1. #include<iostream>
    2. using namespace std;
    3. const int N = 3e5 + 10;
    4. int q[N];
    5. int main()
    6. {
    7. int n;
    8. cin>>n;
    9. char op[2],str[20];
    10. while(n--)
    11. {
    12. scanf("%s%s",op,str);
    13. int x=0;
    14. for(int i=0;str[i];i++)
    15. {
    16. x=x*2+str[i]%2;//相当于字典树写法
    17. //这句话就是将一个数字按照各位置的奇偶性转化为对应的二进制数
    18. //str[i]没有str[i] - '0'的原因是字符'0''1''2''3'...
    19. //对应的ASCII码是4849505148495051…,
    20. //奇偶性相同,可以直接计算。
    21. }
    22. if(*op=='+') q[x]++;
    23. else if(*op=='-') q[x]--;
    24. else printf("%d\n",q[x]);
    25. }
    26. return 0;
    27. }

  • 相关阅读:
    【详细学习SpringBoot自动装配原理分析之核心流程初解析-1】
    [工业自动化-7]:西门子S7-15xxx编程 - PLC主站 - 电源模块
    3D NAND 前沿
    ARP欺骗
    RK3588 实现温控风扇之pwm驱动调试(二)
    WIN7用上最新版Chrome
    JavaScript 62 JavaScript 版本 62.2 JavaScript ES5
    MySQL并行复制(MTS)原理(完整版)
    循环神经网络理论知识+卷积神经网络模型
    Android开发之NDK 编译Pjsip
  • 原文地址:https://blog.csdn.net/m0_63925226/article/details/126450520