匹配价值
匹配价值
给定一个字符串集合 , 中包含 个长度为 的 字符串,集合中可能包含重复元素。
给定一个长度为 的整数序列 。
关于两个长度为 的 字符串 的匹配价值 ,其具体计算方法如下:
- 设字符串 的各位字符从左到右依次为 。
- 设字符串 的各位字符从左到右依次为 。
- 初始时,。
- 对于所有 ,如果 ,则 加上 。
- 最终得到的 即为两字符串的匹配价值。
现在,给定 个询问,每个询问包含一个长度为 的 字符串 以及一个整数 ,具体询问内容为:请你计算并输出集合 中有多少个元素满足,与给定字符串 的匹配价值不大于 。
注意,如果集合中多个相同的元素均满足询问条件,则每个元素均应被计数。
输入格式
第一行包含三个整数 。
第二行包含 个整数 。
接下来 行,每行包含一个长度为 的 字符串,表示集合 中的一个元素。
最后 行,每行包含一个长度为 的 字符串 和一个整数 ,表示一个询问。
输出格式
每个询问输出一行答案,一个整数,表示满足询问条件的元素个数。
数据范围
前 个测试点满足 。
所有测试点满足 ,,,。
输入样例1:
2 4 5 40 20 01 01 10 11 00 20 00 40 11 20 11 40 11 60
输出样例1:
2 4 2 3 4
输入样例2:
1 2 4 100 0 1 0 0 0 100 1 0 1 100
输出样例2:
1 1 2 2 3 1 4 2
解题思路
这题思路是预处理。可以发现直接暴力的话肯定会超时,暴力枚举是为了在集合中统计与字符串匹配权值不超过的个数,因此可以想到把枚举的过程进行预处理,查询的时候就可以控制到。
字符串的最大长度为,因此最多有种不同的字符串,可以预处理两两配对的情况,一共有种情况,这个计算量是可以过的,因此可以先预处理出这种情况,然后算一下每种情况对应的权值是多少。同时在询问的时候权值是不超过的,只有当计算的权值不超过时才记录下来,因此开一个数组表示输入的字符串是,权值为时,集合中与匹配的字符串个数。因为询问求的是权值不超过的情况,因此预处理完后还需要对数组求前缀和。
在字符串进行匹配求权值时用位运算,就可以把这部分的计算量优化到。如果有串和,为了求和中有哪些位是相同的,可以先异或再对结果按位取反,即,因为串的位数不是固定位,这个结果会使得高位全是,因此事实上应该是,其中是串的位数。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1 << 12, M = 110; 5 6 int n, m, k; 7 int w[12], mp[N]; 8 int cnt[N]; 9 int s[N][M]; 10 11 int get(char *str) { 12 int st = 0; 13 // 原字符串低位在前高位在后,转换后01串后低位在后高位在前,因此需要反过来处理 14 for (int i = n - 1; i >= 0; i--) { 15 st = st << 1 | str[i] - '0'; 16 } 17 return st; 18 } 19 20 int main() { 21 scanf("%d %d %d", &n, &m, &k); 22 23 for (int i = 0; i < n; i++) { 24 scanf("%d", w + i); 25 } 26 for (int i = 0; i < 1 << n; i++) { // 预处理2^n种情况对应的权值 27 for (int j = 0; j < n; j++) { 28 if (i >> j & 1) mp[i] += w[j]; 29 } 30 } 31 32 while (m--) { 33 char str[15]; 34 scanf("%s", str); 35 cnt[get(str)]++; // 统计集合中该字符串出现的次数 36 } 37 38 for (int i = 0; i < 1 << n; i++) { // i是询问的字符串 39 for (int j = 0; j < 1 << n; j++) { // j是集合中的字符串 40 int t = i ^ j ^ (1 << n) - 1; // 求i和j相同的位 41 if (mp[t] <= 100) s[i][mp[t]] += cnt[j]; // 如果权值不超过100就累加集合中j的次数(如果不存在j则为0) 42 } 43 } 44 45 for (int i = 0; i < 1 << n; i++) { // 求前缀和 46 for (int j = 1; j <= 100; j++) { 47 s[i][j] += s[i][j - 1]; 48 } 49 } 50 51 while (k--) { 52 char str[15]; 53 int t; 54 scanf("%s %d", str, &t); 55 printf("%d\n", s[get(str)][t]); 56 } 57 58 return 0; 59 }
参考资料
AcWing 4614. 匹配价值(AcWing杯 - 周赛):https://www.acwing.com/video/4317/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16691801.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效