气死我人了

P3167 [CQOI2014] 通配符匹配

这样: ``` #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> namespace my { typedef unsigned long long ull; const int maxn(112345); const ull base(23);//选择的进制数 ull power[maxn];//power[i] = base ^ i,其中'^'表示幂 inline void init_power() { power[0] = 1; for (int i(1); i != maxn; ++i) { power[i] = power[i - 1] * base; } } class string {//自己写的string,封装了一下hash相关的函数 public: string() : end(0) {} char& operator[](int p) { return str[p]; } void clear() { end = 0; } void read() {//读入 end = 0; char c(getchar()); while (c < 'a' || c > 'z') c = getchar(); str[end++] = 'a';//在字符串收尾统一加入相同字符不会影响答案,且避免了结尾、开头是通配符的情况。 do { str[end++] = c; c = getchar(); } while (c >= 'a' && c <= 'z'); str[end++] = 'a'; init_hash(); } bool empty() const { return end == 0; } int size() const { return end; } void push_back(char c) {//向该string中加入字符 if (c == '?') pos.push_back(end);//pos记录了该string所有'?'的位置(原因是我在分段时只调用这个函数向string中加入字符) str[end++] = c; } void init_hash() {//初始化hash,原理如上所述 hash[end] = 0; for (int i(end - 1); i >= 0; --i) { hash[i] = hash[i + 1] * base + str[i]; } } ull gethash(int beg, int len) const {//获得其中某一段的hash值 return hash[beg] - hash[beg + len] * power[len]; } ull gethash() const {//获得整段的hash值,程序中似乎没有用到 return hash[0]; } std::vector<int> pos;//pos记录所有'?'的位置 protected: char str[maxn]; ull hash[maxn]; int end; }seg[20], head, tail, dest;//四者分别是:模板串分出来的每一段,模板串的首,模板串的尾,目标串(询问串) char str[maxn]; int endseg, lenstr;//endseg即分出来的段数 void init_seg(int len) {//把模板串分段 int left(0), right(len - 1); while (left <= right) {//先处理首 if (str[left] == '*') break; head.push_back(str[left++]); } head.init_hash(); int pos(right); while (left <= pos) {//由于尾串大小不定,先找到起始点 if (str[pos] == '*') break; --pos; } for (int i(pos + 1); i <= right; ++i) { tail.push_back(str[i]); } tail.init_hash(); ++left; right = pos; while (left <= right) {//处理出所有的段 if (str[left] == '*') {//每段间的分隔符 if (!seg[endseg].empty())//为避免ab******c的情况,判断一下是否为空 seg[endseg].init_hash(), ++endseg;//非空,初始化hash值 ++left; continue; } else { seg[endseg].push_back(str[left++]);//加入段中 } } if (!seg[endseg].empty()) ++endseg;//如果endseg中有元素,++endseg使其指向超出末端下一位 } inline bool match(int s, int beg) {//常识将段seg[s]与目标串beg处开始的字符串进行匹配 int front(0); for (int i(0); i != seg[s].pos.size(); ++i) {//枚举'?'间的字符串 int len(seg[s].pos[i] - front); if (seg[s].gethash(front, len) != dest.gethash(beg, len)) {//hash值不相等,一定没对上 return false; } beg += len + 1; front += len + 1;//匹配上了,那么继续匹配下一个。+1是表示这里跳了一个字符(即'?') } int len(seg[s].size() - front); if (seg[s].gethash(front, len) != dest.gethash(beg, len)) return false;//最后没有'?'之后可能还有一段需要比较 return true; } inline bool com_seg(int s, int& left, int right) { while (left <= right) {//尝试将段seg[s]与dest在[left, right]间的子串进行匹配 if (match(s, left)) { left += seg[s].size();//如果成功匹配,left就往后跳到下一个需要匹配的起始位置 return true; } ++left;//匹配失败,尝试++left继续匹配 } return false; } inline bool cmpstr(string& a, int x, string& b, int y, int len) {//比较a从x处的长度为len的字符串是否与b从y处开始的长度为len的字符串相等 for (int i(0); i != len; ++i) { if (a[x + i] != b[y + i] && a[x + i] != '?' && b[y + i] != '?') return false; } return true; } void compare() {//整体的匹配 int left(0), right(dest.size() - 1); if (head.size() > dest.size() || tail.size() > dest.size()) {//首、尾串大小对不上,一定错了。 printf("NO\n"); return; } if (!cmpstr(head, 0, dest, 0, head.size())) {//由于插入了'a',模板串的首串一定不是通配符,一定要与目标串的开头匹配。 printf("NO\n"); return; } else { left = head.size(); } if (!cmpstr(tail, 0, dest, right - tail.size() + 1, tail.size())) {//与上同理,匹配尾串 printf("NO\n"); return; } else { right = right - tail.size(); } for (int i(0); i != endseg; ++i) { if (!com_seg(i, left, right)) {尝试将段seg[i]与left到right的字符串匹配(可以跳跃,因为段的收尾都是被抹去的'\*') printf("NO\n"); return; } } printf("YES\n"); } int main() { init_power();//一些初始化和函数调用 int T; scanf("%s%d", str + 1, &T); str[0] = 'a'; str[lenstr = ::strlen(str)] = 'a'; init_seg(++lenstr); while (T--) { dest.read(); compare(); } return 0; } } int main() { return my::main(); } ```
by 陈启旺 @ 2019-04-10 19:29:58


可能是下标越界,访问负下标
by _•́へ•́╬_ @ 2022-08-17 19:02:11


|