洛谷P3167 通配符匹配 [CQOI2014] 字符串
正解:哈希+dp/AC自动机/kmp
解题报告:
这题解法挺多的,所以就分别港下好了QwQ
首先港下hash+dp趴
可以考虑设dp式f[i][j]:匹配到第i个通配符了,下面那个字符串匹配到第j位了是否可行
转移的话就只要关心两个通配符之间的那一段是否相等就好
那判断相等就应该要想到哈希鸭,就做完了
啊有点儿简洁,,,
思路挺简单的主要细节比较多趴,所以我等下直接放代码好了QwQ
然后说下AC自动机
就先按'*'通配符分成几段,然后对每段独立地分别做
然后下面当每段之间相对独立,说下每段内部怎么做
首先在每段内部,按'?'再分成几段,分别插入AC自动机中,建fail指针balabala不讲
然后就直接把整个儿下面的那个串在AC自动机上跑,然后开个数组cnt[]记录原串上的每个节点作为开头能匹配上这一段的多少个小段
然后再遍历一遍这整个儿串判断下,如果cnt==小段的数量就欧克了
然后这儿注意下,就因为它每次都直接整个儿原串上跑一次,所以还要记录一下上一次在原串上匹配到第几位了,强制在这一位之后匹配
两个小细节注意下
第一个是这个其实用了一个贪心的小思想,即尽量在前面匹配,可以证明这显然是对的,懒得证了挺显然的还QwQ
第二个是特判下开头结尾有没有'*',特殊处理下
还有一个不算细节问题,,,只是随手记下QAQ就开AC自动机本来是互相独立的嘛,但是如果每次重新建就要先清空再balabala的,就很麻烦,所以直接新开一个根节点然后一直接着做就好,overr(好像没有表述好,,,直接看我代码趴QAQ
(打完代码的lq又回来补充了,,,还有一个细节就,我开始打都快打完了,突然脑子一抽,就觉得,好像可以直接开struct{}tr[N],这样分别表示每个AC自动机代码打起来就很简单
然后我就全删了,改改改改
改完之后我突然意识到有个问题,,,就我是写的数组型,然后我并不知道每个串长的上界,只知道所有串长的上界,内存就会爆炸,所以提醒一下不要这么写,,,当然如果你是指针玩家当然麻油关系QAQ
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define ll unsigned long long
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
+;
char ch[N],s[N];
int nod_cnt,cnt[N],n,rt[N],num,str_cnt[N],lst,lin_cnt;
bool bg,ls;
struct node
{
],fail;}tr[N];vector<int>ed[N];queue<int>Q;
il void insert(ri l,ri r,ri id,ri num)
{
ri nw=rt[num];
rp(i,l,r)
{
])tr[nw].to[s[i]-]=++nod_cnt;
nw=tr[nw].to[s[i]-];
}
ed[nw].push_back(id);
}
il void get_fail(ri num)
{
rp(i,,)if(tr[rt[num]].to[i])Q.push(tr[rt[num]].to[i]),tr[tr[rt[num]].to[i]].fail=rt[num];else tr[rt[num]].to[i]=rt[num];//,printf("to=%d\n",tr[rt[num]].to[i]);
while(!Q.empty())
{
ri nw=Q.front(),sz=ed[tr[nw].fail].size();Q.pop();
rp(i,,sz-)ed[nw].push_back(ed[tr[nw].fail][i]);
rp(i,,)
if(tr[nw].to[i])Q.push(tr[nw].to[i]),tr[tr[nw].to[i]].fail=tr[tr[nw].fail].to[i];
else tr[nw].to[i]=tr[tr[nw].fail].to[i];//,printf("to=%d\n",tr[nw].to[i]);
}
}
il void bd(ri l,ri r,ri num)
{
rt[num]=++nod_cnt;
for(ri i=l;i<=r;++i)
if(s[i]!='?')
{
ri pos=i;
while(pos<=r && s[pos]!='?')++pos;
--pos;
insert(i,pos,pos-l+,num);
++str_cnt[num];
i=pos;
}
get_fail(num);
}
il bool fd(ri num,ri l,ri r,rb fr,rb nd)
{
ri nw=rt[num];memset(cnt,,sizeof(cnt));
rp(i,,n)
{
nw=tr[nw].to[ch[i]-];ri sz=ed[nw].size();
rp(j,,sz-){)++cnt[i-ed[nw][j]+];}
}
rp(i,lst+,n)
{
if(cnt[i]==str_cnt[num])
{
)
{
)continue;
if(nd && !ls && i+r-l!=n)continue;
// printf("%d\n",lst);
lst=i+r-l;;
}
if(nd && !ls && i+r-l!=n)continue;
// printf("%d\n",lst);
lst=i+r-l;;
}
}
;
}
}tr;
il int read()
{
rc ch=gc;ri x=;rb y=;
'))ch=gc;
;
)+(x<<)+(ch^'),ch=gc;
return y?x:-x;
}
int main()
{
// freopen("3167.in","r",stdin);//freopen("3167.out","w",stdout);
scanf();ri lth=strlen(s+);bg=s[]=='*';ls=s[lth]=='*';while(lth && s[lth]=='*')--lth;
;i<=lth;++i)if(s[i]!='*'){ri pos=i;while(s[pos]!='*' && pos<=lth)++pos;--pos;tr.bd(i,pos,++lin_cnt);i=pos;}
ri T=read();
while(T--)
{
scanf();n=strlen(ch+);if(!lth){printf("YES\n");continue;}
lin_cnt=;rb flg=;lst=;
;i<=lth;++i)
if(s[i]!='*')
{
ri pos=i;while(s[pos]!='*' && pos<=lth)++pos;++lin_cnt;--pos;
;break;}
i=pos;
}
flg?printf("NO\n"):printf("YES\n");
}
;
}
kmp我麻油get,,,但是听说和AC自动机很像,,,?所以我先把前两个的代码打了然后可能明天或者以后想起来了再想下kmp怎么做,,,想起来了就写想不出来就当没有kmp这个算法TT
洛谷P3167 通配符匹配 [CQOI2014] 字符串的更多相关文章
- 洛谷 P3370 【模板】字符串哈希
洛谷 P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的 ...
- 【洛谷P3709】大爷的字符串题
看这题网上居然还没人写blog,怕是都去看洛谷自带的了-- 你才是字符串!你全家都是字符串!这题跟字符串没多大关系,只是出题人lxl想要吐槽某中学而已--... 其实这题说白了就是问区间里出现最多的数 ...
- 【洛谷4173】残缺的字符串(重拾FFT)
点此看题面 大致题意: 有一个长度为\(n\)的字符串\(A\)和一个长度为\(m\)的字符串\(B\),其中存在一些字符'*'可以与任意字符匹配.求\(B\)中所有满足条件的位置,使得从这一位置开始 ...
- 【洛谷P4173】残缺的字符串
题目大意:给定一个文本串和一个模板串,串中含有通配符,求文本串中有多少个位置可以与文本串完全匹配. 题解:利用卷积求解字符串匹配问题. 通配符字符串匹配的数值表示为 \[\sum\limits_{i ...
- 洛谷P3370 【模板】字符串哈希
P3370 [模板]字符串哈希 143通过 483提交 题目提供者HansBug 标签 难度普及- 提交 讨论 题解 最新讨论 看不出来,这题哪里是哈希了- 题目描述 如题,给定N个字符串(第i个 ...
- 洛谷P1140 基因匹配 //DP真正意义上的一血
题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了44种核苷酸,简记作A,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类基因工作组的任务 ...
- [洛谷P4925][1007]Scarlet的字符串不可能这么可爱
题目大意:问字符集大小为$k$,长度为$L$的字符串,且没有长度超过$1$的回文段的个数.规定第$s(若为0则无限制)$位为$w$. 题解:懒得写了,根据是否有限制分类讨论 卡点:中途有个地方忘记取模 ...
- 洛谷 2543 [AHOI2004]奇怪的字符串
题目描述 输入输出格式 输入格式: 输入文件中包含两个字符串X和Y.当中两字符串非0即1.序列长度均小于9999. 输出格式: X和Y的最长公共子序列长度. 输入输出样例 输入样例#1: 010101 ...
- 洛谷—— P2543 [AHOI2004]奇怪的字符串
P2543 [AHOI2004]奇怪的字符串 题目描述 输入输出格式 输入格式: 输入文件中包含两个字符串X和Y.当中两字符串非0即1.序列长度均小于9999. 输出格式: X和Y的最长公共子序列长度 ...
随机推荐
- 【PHP】解析PHP的GD库
官方文档:http://php.net/manual/en/book.image.php 1.GD库简介 PHP可以创建和操作多种不同格式的图像文件.PHP提供了一些内置的图像信息函数,也可以使用GD ...
- [ci]容器ci索引
伙计们: 有任何意见或建议或看不懂的请在对应的文章下留言(请注明上下文) 我会及时改动. 这是以前的一些在物理机上搞过 [ci]容器ci索引 http://www.cnblogs.com/iiiihe ...
- Asp.Net \uxxx Unicode编码解码
/// <summary> /// Unicode编码 /// </summary> /// <param name="str"></pa ...
- [Unity]Unity常见API
本文主要为了方便查阅 1. MonoBehaviour 生命周期 Awake 对象创建的时候调用,类似构造函数 Start 在Awake之后执行,区别在于,如果组件不可用(在Inspector没有勾选 ...
- C语言 · 还款计算
标题: 还款计算 银行贷款的等额本息还款方法是: 每月还固定的金额,在约定的期数内正好还完(最后一个月可能会有微小的零头出入). 比如说小明在银行贷款1万元.贷款年化利率为5%,贷款期限为24个月. ...
- hdoj:2081
手机短号 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- js 时间戳转时间工具类 js时间戳与时间互转
/** * 时间戳格式化函数 * @param {string} format 格式 * @param {int} timestamp 要格式化的时间 默认为当前时间 * @return {strin ...
- Window 产品密钥
2019.4.2 测试可用 window2003 DF74D-TWR86-D3F4V-M8D8J-WTT7M
- win10下VS2017配置GSL库
GSL库:GNU Scientific Library 1. 下载:下载Complete package, except sources和Sources两个exe文件 2. 安装:将两个exe安装 ...
- sublime 安装ctags跳转以及跳转快捷键
在source insight中有一个很好用的功能,就是函数的跟踪跳转,在阅读别人的代码的时候轻松的浏览原函数.我们知道,在使用vim的时候有个插件叫ctags,同理,在sublime text中也能 ...