【HNOI2014】抄卡组
题面
题解
如果所有的字符串都有通配符,那么只要比较不含通配符的前缀和后缀就可以了。
否则一定有一个串没有通配符。找出这个字符串,然后将所有串与这个串匹配,通配符将\(B\)分成一段一段在\(A\)上匹配,然后越早出现越好,这里用\(\mathrm{KMP, hash}\)都可以
讲起来容易,但是写起来的话就有点复杂了
时间复杂度:\(\mathrm{O}(\sum \mid S_i\mid)\)
代码复杂度:\(\mathrm{O}(\infty)\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#include<string>
#define RG register
const unsigned long long X(60923);
unsigned long long val[10000010];
const int maxn(100010);
std::string s[maxn], s1[maxn];
std::vector<unsigned long long> h[maxn];
std::vector<int> pos[maxn];
inline int cmp(const std::string &lhs, const std::string &rhs)
{ return lhs.length() < rhs.length(); }
int T, n;
void calc(int i)
{
pos[i].clear(), h[i].clear();
pos[i].push_back(-1), h[i].push_back(0);
for(std::string::iterator it = s[i].begin(); it != s[i].end(); ++it)
{
h[i].push_back(h[i].back() * X + *it);
if(*it == '*') pos[i].push_back(it - s[i].begin());
}
pos[i].push_back(s[i].length());
}
inline unsigned long long Hash(const std::vector<unsigned long long> &vec,
int l, int r)
{
++l, ++r;
return vec[r] - vec[l - 1] * val[r - l + 1];
}
bool check(int x, int y)
{
int lenx = s[x].length(), leny = s[y].length();
if(s[y].find('*') != std::string::npos)
std::swap(x, y), std::swap(lenx, leny);
if(s[x].find('*') == std::string::npos
&& s[y].find('*') == std::string::npos)
return Hash(h[x], 0, s[x].length() - 1) == Hash(h[y], 0, s[y].length() - 1);
else
{
std::string A = ""; std::string::size_type p = 0;
for(RG int i = 1; i < pos[x].size(); i++)
{
int tpos = p, len = pos[x][i] - pos[x][i - 1] - 1;
while(tpos + len - 1 < s[y].length() &&
Hash(h[x], pos[x][i - 1] + 1, pos[x][i] - 1)
!= Hash(h[y], tpos, tpos + len - 1)) ++tpos;
if(tpos + len - 1 >= s[y].length()) return false;
if(tpos != 0 && p == 0) return false;
p = tpos + len;
}
return true;
}
}
void Doit()
{
int pos = -1;
for(RG int i = 1; i <= n; i++) calc(i);
for(RG int i = 1; i <= n; i++)
if(s[i].find('*') == std::string::npos) { pos = i; break; }
if(pos == -1)
{
for(RG int i = 1; i <= n; i++)
{
s1[i] = "";
for(RG int j = 0; j < s[i].length(); j++)
if(s[i][j] == '*') break;
else s1[i] += s[i][j];
}
std::sort(s1 + 1, s1 + n + 1, cmp);
for(RG int i = 2; i <= n; i++)
{
for(RG int j = 0; j < s1[i - 1].length(); j++)
if(s1[i][j] != s1[i - 1][j])
return (void)(std::cout << 'N' << std::endl);
}
for(RG int i = 1; i <= n; i++)
{
s1[i] = "";
for(RG int j = s[i].length() - 1; ~j; j--)
if(s[i][j] == '*') break;
else s1[i] += s[i][j];
}
std::sort(s1 + 1, s1 + n + 1, cmp);
for(RG int i = 2; i <= n; i++)
{
for(RG int j = 0; j < s1[i - 1].length(); j++)
if(s1[i][j] != s1[i - 1][j])
return (void)(std::cout << 'N' << std::endl);
}
}
else for(RG int i = 1; i <= n; i++)
{
if(i == pos) continue;
// std::cout << i << std::endl;
if(!check(i, pos)) return (void)(std::cout << 'N' << std::endl);
}
std::cout << 'Y' << std::endl;
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin >> T, val[0] = 1;
for(RG int i = 1; i <= 10000000; i++) val[i] = val[i - 1] * X;
while(T--)
{
std::cin >> n;
for(RG int i = 1; i <= n; i++)
std::cin >> s[i];
Doit();
}
return 0;
}
【HNOI2014】抄卡组的更多相关文章
- bzoj3574[Hnoi2014]抄卡组
http://www.lydsy.com/JudgeOnline/problem.php?id=3574 我们发现如果所有的字符串都有*,那么只需要比较他们的“前缀”和“后缀”相同即可.“前缀”指第一 ...
- luogu P3234 [HNOI2014]抄卡组
传送门 nmdwsm 自己看吧,不想写了qwq 垃圾代码如下 和题解完全不一样 #define LL long long #define uLL unsigned long long #define ...
- 【LG3234】[HNOI2014]抄卡组
题面 题解 分三种情况: 若所有串都没有通配符,直接哈希比较即可. 若所有串都有通配符, 把无通配符的前缀 和 无通配符的后缀哈希后比较即可. 中间部分由于通配符的存在,一定可以使所有串匹配. 若部分 ...
- BZOJ3574 HNOI2014抄卡组(哈希)
容易发现通配符中间的部分可以任意匹配,会造成的无法匹配的仅仅是前后缀,前缀和后缀可以分别独立处理.如果字符串均有通配符,只需要按前/后缀长度排序然后暴力匹配就可以了. 问题在于存在无通配符的字符串.显 ...
- [HNOI2014]抄卡组
[Luogu3234] [LOJ2208] 题解及代码 锻炼哈希码力的一道题 , 具体细节见代码 #include<cstdio> #include<cstring> #inc ...
- 洛谷P3234 抄卡组 [HNOI2014] 字符串hash
正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...
- 【LOJ6254】最优卡组 堆(模拟搜索)
[LOJ6254]最优卡组 题面 题解:常用的用堆模拟搜索套路(当然也可以二分).先将每个卡包里的卡从大到小排序,然后将所有卡包按(最大值-次大值)从小到大排序,并提前处理掉只有一张卡的卡包. 我们将 ...
- HearthBuddy卡组
偶数萨 手打两天已上传说,各位加油 欧洲牧羊人 ### 火元素换艾雅# 职业:萨满祭司# 模式:狂野模式## 2x (2) 图腾魔像 # 2x (2) 大漩涡传送门 # 2x (2 ...
- 服务器&阵列卡&组raid 5
清除raid信息后,机器将会读不到系统, 后面若进一步操作处理, raid信息有可能会被初始化掉,那么硬盘数据就有可能会被清空, 导致数据丢失, 否则如果只是清除raid信息,重做raid是可以还原系 ...
随机推荐
- C# 数据上传(自用笔记)
#region 数据上传 [HttpPost] public ActionResult UploadFile() { HttpFileCollectionBase files = Request.Fi ...
- C#.NET里面抽象类,接口,虚方法
1抽象类 (1) 抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法 (2) 抽象类不能被实例化 (3) 抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明 ...
- [翻译] CNPPopupController
CNPPopupController CNPPopupController is a simple and versatile class for presenting a custom popup ...
- 设计标签选择器TitleSwitch
设计标签选择器TitleSwitch 效果如下: 源码如下: TitleSwitch.h 与 TitleSwitch.m // // TitleSwitch.h // TitleSwitch // / ...
- PHPredis安装
一.PHPredis下载链接:https://pan.baidu.com/s/1bz0EaJgDpp2ADQJCJOHJGA 二.解压并进入目录 三.发现没有configure文件,需要安装autoc ...
- 发现微信支付bug
第一张银行卡支付金额不足无法付款,选择另一张同样密码的银行卡,居然不用重新输入密码即可直接付款成功!
- November 10th 2016 Week 46th Thursday
Live like you were dying, love because you do. 生如将逝,爱自本心. When faced with our darkest hour, hope is ...
- right here waiting的歌词
right here waiting的歌词 2006-12-30 17:36 匿名 | 分类:音乐 | 该问题已经合并到>> right here waiting的歌词有吗? 扫描二维 ...
- Ubuntu通过Pyenv管理python版本
网上安装使用Pyenv的教程很多,但是实测有很多教程有坑,经过多家比较发现下面的教程可用,内容全面,与大家分享. 首先安装pyenv全家桶 curl -L https://raw.githubuser ...
- 【Alpha】Daily Scrum Meeting 集合贴
coding:https://git.coding.net/hmCoding/LearnTGP.git 11月14日:http://www.cnblogs.com/polk-blogs/p/78270 ...