【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是可以还原系 ...
随机推荐
- Common administrative commands in Red Hat Enterprise Linux 5, 6, and 7
https://access.redhat.com/articles/1189123 Common administrative commands in Red Hat Enterprise Linu ...
- 浅析Oracle 12c中Data Guard新特性
浅析Oracle 12c中Data Guard新特性 写在前面 无论是做Oracle运维的小伙伴还是老伙伴,想必对Oracle数据库的数据级灾备核心技术—Data Guard是再熟悉不过了!这项从 ...
- zabbix日常监控项java(四又分之一)
因zabbix自带监控JMX的模板通用性差的问题,需要我们自己新建一个属于自己的模板,于是本文就出现了.... 大部分都是参考网上其他博主的文档,在此作为梳理.总结:以方便自己日后使用查询.
- 学习博客之Java继承多态接口
这一篇博客主要是对软工前一阶段学习的总结,主要是对Java的学习总结,包括三部分:Java的继承.多态和接口 Java的继承 继承是面向对象的三大特性之一,能够实现软件的复用. Java子类继承父类的 ...
- 2.2 IPython基础
2.2 IPython基础 1 Running the IPython Shell (运行IPython Shell) 可以通过命令行启动IPython,就像启动标准的Python解释器一样,直接在t ...
- PostgreSQL学习----模式schema
PostgreSQL学习---模式schema 小序 接触PostgreSQL也有好长时间了,知识不总结梳理,似乎总不是自己的,继续努力吧少年!以此记录我的软件工艺之路! 模式(Schema) 一个 ...
- Mybatis 的常见面试题
背景:好久没用Mybatis了,有些面试题还是要好好准备的. Mybatis 的常见面试题
- Spring Boot中使用EhCache实现缓存支持
SpringBoot提供数据缓存功能的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存.,相信非常多人已经用过cache了.因为数据库的IO瓶颈.一般情况下我们都会引入非常多的缓存策略, ...
- React 如何正常渲染一段HTML字符串
dangerouslySetInnerHTMl 属性 很多时候我们做一个项目接口会返回一段 HTML 字符串文本,然后我们把它解析渲染成正常的html,这是在项目中常见不能再常见的情况了,可是在 re ...
- 【转】纯JS省市区三级联动(行政区划代码更新至2015-9-30)
本文代码实现的功能是省市区三级联动下拉列表,纯Javascript,网上已有很多这方面的代码.但是作为一个新手,这是我的第一篇CSDN博客,发此文的目的主要是学习交流,希望看到的朋友发现有什么不对的地 ...