首页 > 代码库 > BZOJ 3574 HNOI 2014 抄卡组 字符串Hash+STL
BZOJ 3574 HNOI 2014 抄卡组 字符串Hash+STL
题目大意:给出一些表示卡组的字符串,字符串中可能出现‘*’符号(并不是BZ上以前写的‘#’号,更不是“ ‘*’ ”。。。),这个符号可以代表任意字符串(包括空串)。问所有的字符串是否能够相同。
思路:题目描述,样例有误,数据范围坑爹,官方数据出错,BZ输入流过大RE。。这题做完了都不知道该说什么好了。。。
整个就是一个常数很大的O(n)模拟题而已。。。
首先数据范围十分坑爹,N*最长字符串长度<=2*10^8,你这让我怎么开数组?好吧,那就全篇vector
先弄出所有字符串的Hash值,之后分三种情况讨论:
1.所有的字符串中都不含通配符。这种情况很简单,只要比较所有字符串的Hash值就行了。
2.所有字符串都含有通配符。注意到通配符可以代替任意字符串,那我们不管中间的通配符了,只需要看前缀和后缀。前缀是从开头到第一个通配符,后缀同理。按照前缀从短到长排序,然后逐个判断前缀是否相等,后缀同理。中间的通配符肯定能自己搞成一样的。
3.有的字符串中含有通配符,有的字符串中不含有通配符。先把不含有通配符的字符串比较一下,然后就是让所有含有通配符的字符串变成不含有通配符的字符串那样就行了。按照上一种情况的想法,先把前缀和后缀去掉,然后让含有通配符的那个的中间部分匹配上不含有通配符的中间部分的字符串。直接暴力就行了,反正怎么弄都是O(n)。利用通配符分割含有通配符的中间部分,然后用一个指针去不含有通配符的字符串中扫。
注意各种边界讨论;此外不能使用cin,cout等流,可能导致流过大而RE(我会说因为这个破事调了一个点?谁向BZ反映一下啊。。。
但是用了大量的STL不用cin怎么搞?可行的方法是关闭流的同步(详情见代码)。至于为什么可行,谜。
CODE:
#include <vector> #include <string> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define BASE 2333 using namespace std; unsigned long long power[10000010]; bool flag; struct Complex{ int wildcard,length; vector<unsigned long long> hash; vector<int> card; bool operator <(const Complex &a)const { return flag ? card[1] < a.card[1]:length - card[wildcard] < a.length - a.card[a.wildcard]; } void Reset() { wildcard = length = 0; hash.clear(); hash.push_back(0); card.clear(); card.push_back(0); } void GetHash(string s) { for(string::iterator it = s.begin(); it != s.end(); ++it) { hash.push_back(hash.back() * BASE + *it); ++length; if(*it == '*') { ++wildcard; card.push_back(length); } } } unsigned long long GetHash(int l,int r)const { return hash[r] - hash[l - 1] * power[r - l + 1]; } bool Pair(const Complex &p) { int suffix_len = length - card[wildcard]; if(p.length < suffix_len + card[1] - 1) return false; if(GetHash(1,card[1] - 1) != p.GetHash(1,card[1] - 1)) return false; if(GetHash(card[wildcard] + 1,length) != p.GetHash(p.length - suffix_len + 1,p.length)) return false; int st = card[1],ed = p.length - suffix_len; for(int i = 1; i < wildcard; ++i) { int len = card[i + 1] - card[i] - 1; unsigned long long h = GetHash(card[i] + 1,card[i + 1] - 1); while(1) { if(st + len - 1 > ed) return false; if(p.GetHash(st,st + len - 1) == h) { st += len; break; } ++st; } } return true; } }src[MAX]; int T,cnt; string temp; void Pretreatment() { power[0] = 1; for(int i = 1; i <= 10000000; ++i) power[i] = power[i - 1] * BASE; } inline void Initialize() { for(int i = 1; i <= cnt; ++i) src[i].Reset(); } inline bool Judge() { unsigned long long no_card = 0; int p = 0; for(int i = 1; i <= cnt; ++i) if(!src[i].wildcard) { if(!p) no_card = src[i].hash[src[i].length],p = i; else if(no_card != src[i].hash[src[i].length]) return false; } if(p) { for(int i = 1; i <= cnt; ++i) if(src[i].wildcard) if(!src[i].Pair(src[p])) return false; } else { flag = true; sort(src + 1,src + cnt + 1); for(int i = 1; i < cnt; ++i) if(src[i].GetHash(1,src[i].card[1] - 1) != src[i + 1].GetHash(1,src[i].card[1] - 1)) return false; flag = false; sort(src + 1,src + cnt + 1); for(int i = 1; i < cnt; ++i) { int suffix_len = src[i].length - src[i].card[src[i].wildcard]; if(src[i].GetHash(src[i].card[src[i].wildcard] + 1,src[i].length) != src[i + 1].GetHash(src[i + 1].length - suffix_len + 1,src[i + 1].length)) return false; } } return true; } int main() { ios::sync_with_stdio(false); Pretreatment(); for(cin >> T; T--;) { cin >> cnt; Initialize(); for(int i = 1; i <= cnt; ++i) { cin >> temp; src[i].GetHash(temp); } puts(Judge() ? "Y":"N"); } return 0; }
BZOJ 3574 HNOI 2014 抄卡组 字符串Hash+STL