题型:字符串
题意:
n个字符串,m次操作,每次操作刷k次条形码。
条形码有宽度,分为窄码和宽码,二者宽度大致为二倍,误差不大于5%。
每个条形码代表一个ASCII码,窄码为0,宽码为1,刷一次可以得到一个字母,每次操作,可以获得对应的k长度的字符串,然后去n个字符串中找具有相同前缀的字符串的个数。
问最终共有查询出的字符串的总数。
分析:
由于条形码的宽度有误差,在判断宽窄的时候,先找出最窄的宽度,然后看,如果当前的宽度与最窄宽度之差与最窄宽度的比小于20%,就可以认为当前宽度为0,否则为1.
由于有10^4个字符串,所以需要降低查找时间,采用字典树处理即可。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define inf 1e+12
#define eps 1e-8
#define M 100010
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
class Trie_tree {
struct node {
int next[26],ptr,num;
void init() {
ptr=-1;
num=0;
mt(next,0);
}
} s[M];
int ls,p;
int f(char c) {
return c-'a';
}
public:
void init() {
s[1].init();
p=0;
ls=2;
}
void Insert(char ch[]) {
int head=1;
for(int k=0; ch[k]; k++) {
int id=f(ch[k]);
if(!s[head].next[id]) {
s[head].next[id]=ls;
s[ls++].init();
}
head=s[head].next[id];
s[head].num++;
}
s[head].ptr=p++;
}
int query(char ch[],int op) {
int head=1;
for(int k=0; ch[k]&&head; k++) {
head=s[head].next[f(ch[k])];
}
if(op) {
if(head) return s[head].ptr;
return -1;
} else {
if(head) return s[head].num;
return 0;
}
}
} ts;
char str[123];
double ma[10];
int main() {
int n,m;
while(~scanf("%d%d",&n,&m)) {
ts.init();
for(int i=0; i<n; i++) {
scanf("%s",&str);
ts.Insert(str);
}
int ans = 0;
while(m--) {
int k;
scanf("%d",&k);
mt(str,0);
int pre = 0;
for(int i=0; i<k; i++) {
double minma = inf;
for(int j=0; j<8; j++) {
scanf("%lf",&ma[j]);
minma = min(minma,ma[j]);
}
int bin[10];
for(int j=0; j<8; j++) {
if((ma[j] - minma)/minma<0.2) {
bin[j] = 0;
} else {
bin[j] = 1;
}
}
int val = 0;
int mul = 1;
for(int j=7;j>=0;j--){
val += mul * bin[j];
mul *= 2;
}
str[pre] = val;
pre++;
}
ans += ts.query(str,0);
}
printf("%d\n",ans);
}
return 0;
}