题面

题解

如果所有的字符串都有通配符,那么只要比较不含通配符的前缀和后缀就可以了。

否则一定有一个串没有通配符。找出这个字符串,然后将所有串与这个串匹配,通配符将\(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】抄卡组的更多相关文章

  1. bzoj3574[Hnoi2014]抄卡组

    http://www.lydsy.com/JudgeOnline/problem.php?id=3574 我们发现如果所有的字符串都有*,那么只需要比较他们的“前缀”和“后缀”相同即可.“前缀”指第一 ...

  2. luogu P3234 [HNOI2014]抄卡组

    传送门 nmdwsm 自己看吧,不想写了qwq 垃圾代码如下 和题解完全不一样 #define LL long long #define uLL unsigned long long #define ...

  3. 【LG3234】[HNOI2014]抄卡组

    题面 题解 分三种情况: 若所有串都没有通配符,直接哈希比较即可. 若所有串都有通配符, 把无通配符的前缀 和 无通配符的后缀哈希后比较即可. 中间部分由于通配符的存在,一定可以使所有串匹配. 若部分 ...

  4. BZOJ3574 HNOI2014抄卡组(哈希)

    容易发现通配符中间的部分可以任意匹配,会造成的无法匹配的仅仅是前后缀,前缀和后缀可以分别独立处理.如果字符串均有通配符,只需要按前/后缀长度排序然后暴力匹配就可以了. 问题在于存在无通配符的字符串.显 ...

  5. [HNOI2014]抄卡组

    [Luogu3234] [LOJ2208] 题解及代码 锻炼哈希码力的一道题 , 具体细节见代码 #include<cstdio> #include<cstring> #inc ...

  6. 洛谷P3234 抄卡组 [HNOI2014] 字符串hash

    正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...

  7. 【LOJ6254】最优卡组 堆(模拟搜索)

    [LOJ6254]最优卡组 题面 题解:常用的用堆模拟搜索套路(当然也可以二分).先将每个卡包里的卡从大到小排序,然后将所有卡包按(最大值-次大值)从小到大排序,并提前处理掉只有一张卡的卡包. 我们将 ...

  8. HearthBuddy卡组

    偶数萨 手打两天已上传说,各位加油  欧洲牧羊人 ### 火元素换艾雅# 职业:萨满祭司# 模式:狂野模式## 2x (2) 图腾魔像        # 2x (2) 大漩涡传送门   # 2x (2 ...

  9. 服务器&阵列卡&组raid 5

    清除raid信息后,机器将会读不到系统, 后面若进一步操作处理, raid信息有可能会被初始化掉,那么硬盘数据就有可能会被清空, 导致数据丢失, 否则如果只是清除raid信息,重做raid是可以还原系 ...

随机推荐

  1. C#对DataTable里数据排序的方法

    protected void Page_Load(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Ad ...

  2. 修改UIView的默认Layer后,修改View的值会动态修改Layer的值

    修改UIView的默认Layer后,修改View的值会动态修改Layer的值 效果图: 如上图所示,当我们修改了一个UIView的子类中的Layer内置类型时(如上图中我们将CALayer直接替换成了 ...

  3. Linux crontab命令详解

    crontab:定时任务的守护进程,精确到分,设计秒的我们一般写脚本  -->相当于闹钟        日志文件:  ll /var/log/cron*        编辑文件: vim /et ...

  4. Vue安装以及Vue项目创建以及Vue Devtools安装

    这几天一直在学习Vue.js框架. 因为以前没有前端项目的经验,也没学过什么前端框架,所以,对于vue.js的学习有些不知所措. 在vue.js官网看教程,按照教程指点,可以不用脚手架开发,也可以搭建 ...

  5. (1)构造方法和方法重载 (2)this关键字 (3)方法的传参和递归调用

    1.构造方法和方法重载如: Person p = new Person(); - 声明Person类型的引用p指向Person类型的对象 p.show(); - 调用名字为show()的成员方法 1. ...

  6. Deadline下:写论文的总结

    终于赶在了11月底截止的时刻提交上了导航年会的论文.三天加上两个半晚上差不多干完了80%的活,无论是否能够被录,这次的写作收获很大. 认识到了: 1. 读文献时,一定要带着问题,如果是我来做,我会怎么 ...

  7. log4j.properties的配置详解

    log4j.rootLogger=ERROR,A1log4j.appender.A1=org.apache.log4j.ConsoleAppenderlog4j.appender.A1.layout= ...

  8. 禁用wps的云文档,恢复到清爽的状态

    wps安装完成后,默认会开启云文档功能,每次打开表格.文档都会显示乱七八糟的一些东西,很麻烦 不得已只好手动为wps“瘦身”: 在wps表格或者文档的快捷方式上右键,选择打开文件所在位置 找到一个最新 ...

  9. 【bzoj4543】[POI2014]Hotel加强版

    题目 抄题解.jpg 发现原来的\(O(n^2)\)的换根\(dp\)好像行不通了呀 我们考虑非常牛逼的长链剖分 我们设\(f[x][j]\)表示在\(x\)的子树中距离\(x\)为\(j\)的点有多 ...

  10. Loj #2256. 「SNOI2017」英雄联盟

    题目 我就是个丝薄 如果要用\(dp_i\)表示凑出\(i\)的最小花费显然不可能的 之后大力猜想能凑出来的状态不会很多,我的暴力也告诉我不是很多,好像也确实不多的样子,大概\(4e4\)左右 但是我 ...