「题解报告」 P3167 [CQOI2014]通配符匹配

思路

*?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配。

我们首先把原字符串分成多个以一个通配符开头的字符串,如将 happy*birthdey?xingchen 分成:

happy
*birthday
?xingchen

然后设原串有 \(m\) 个通配符, \(op_i\) 表示分出来的第 \(i\) 个串前的通配符(\(0\) 没有,\(1\) 是?,\(2\) 是*),\(len_i\) 表示分出来的第 \(i\) 个串的长度,\(f_{i,j}\) 表示分出来的第 \(i\) 个串的结尾能否匹配上当前查询的字符串的位置 \(j\)。

则转移方程显然为:

\[f_{i,j}=
\begin{cases}
f_{i-1,j-len_i}&op_i=0\\
f_{i-1,j-len_i-1}&op_i=1\\
\sum_{k=0}^{j-len}f_{i-1,j-len_i}&op_i=2\\
\end{cases}
\]

能否转移直接用 Hash \(\Theta(1)\) 比较即可。

初始状态 \(f_{0,0}=1\),答案为 \(f_{m,\left|S\right|}\),时间复杂度 \(\Theta(mn\left|S\right|)\)。

代码

const ll N=1e5+10,inf=1ll<<40;
ll T,n,m=1,ln,ans;
ll a1[20],a2[20],len[20],op[20];
ll f[20][N],sm[N];
char s[N],t[N];
class Hash{
public:
const ll P1=315716521,P2=475262633;
ll h1[N],h2[N],z1[N],z2[N];
inline void Init(char *s){
z1[0]=z2[0]=1;
ll length=strlen(s+1);
_for(i,1,length){
z1[i]=z1[i-1]*233%P1;
z2[i]=z2[i-1]*233%P2;
h1[i]=(h1[i-1]*233+s[i]-'a'+1)%P1;
h2[i]=(h2[i-1]*233+s[i]-'a'+1)%P2;
}
return;
}
inline ll GetHash1(ll l,ll r){return (h1[r]-h1[l-1]*z1[r-l+1]%P1+P1)%P1;}
inline ll GetHash2(ll l,ll r){return (h2[r]-h2[l-1]*z2[r-l+1]%P2+P2)%P2;}
}b;
namespace SOLVE{
inline ll rnt(){
ll x=0,w=1;char c=getchar();
while(!isdigit(c)){if(c=='-')w=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*w;
}
inline ll GetA1(char *awa){
ll hash_val=0;
ll length=strlen(awa+1);
_for(i,1,length)hash_val=(hash_val*233+awa[i]-'a'+1)%b.P1;
return hash_val;
}
inline ll GetA2(char *awa){
ll hash_val=0;
ll length=strlen(awa+1);
_for(i,1,length)hash_val=(hash_val*233+awa[i]-'a'+1)%b.P2;
return hash_val;
}
inline void Pre(){
char qwq[N];
_for(i,1,n){
if(s[i]=='?'||s[i]=='*'){
if(i==1)--m;
a1[m]=GetA1(qwq);
a2[m]=GetA2(qwq);
memset(qwq,0,sizeof(qwq));
op[++m]=(s[i]=='?')?1:2;
}
else qwq[++len[m]]=s[i];
}
a1[m]=GetA1(qwq);
a2[m]=GetA2(qwq);
return;
}
inline bool Check(ll a,ll i){
if(a1[a]!=b.GetHash1(i-len[a]+1,i))return 0;
if(a2[a]!=b.GetHash2(i-len[a]+1,i))return 0;
return 1;
}
inline void PP(){
f[0][0]=1;
_for(i,0,ln)sm[i]=1;
_for(i,1,m){
_for(j,0,ln)f[i][j]=0;
for_(j,ln,len[i]){
if(Check(i,j)){
if(op[i]==0)f[i][j]=f[i-1][j-len[i]];
else if(op[i]==1)f[i][j]=f[i-1][j-len[i]-1];
else f[i][j]=sm[j-len[i]];
}
}
sm[0]=0;
_for(j,1,ln)sm[j]=sm[j-1]|f[i][j];
}
return;
}
inline void In(){
scanf("%s",s+1);
n=strlen(s+1),Pre();
T=rnt();
while(T--){
scanf("%s",t+1);
b.Init(t),ln=strlen(t+1);
PP(),puts(f[m][ln]?"YES":"NO");
}
return;
}
}

「题解报告」 P3167 [CQOI2014]通配符匹配的更多相关文章

  1. P3167 [CQOI2014]通配符匹配 题解

    题目 题目大意 给出一个字符串,其中包含两种通配符 ‘?’和 ‘*’ ,‘?’可以代替一个字符,‘*’可以代替一个字符串(长度可以为0) 然后给出几个字符转,判断能否用给出的字符串表示出来 样例解释 ...

  2. 「题解报告」P4577 [FJOI2018]领导集团问题

    题解 P4577 [FJOI2018]领导集团问题 题解区好像没有线段树上又套了二分的做法,于是就有了这片题解. 题目传送门 怀着必 WA 的决心交了两发,一不小心就过了. 题意 求一个树上最长不下降 ...

  3. 「题解报告」P2154 虔诚的墓主人

    P2154 虔诚的墓主人 题解 原题传送门 题意 在 \(n\times m\) 一个方格上给你 \(w\) 个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数. \(1 \le N, M ...

  4. 「题解报告」SP16185 Mining your own business

    题解 SP16185 Mining your own business 原题传送门 题意 给你一个无向图,求至少安装多少个太平井,才能使不管那个点封闭,其他点都可以与有太平井的点联通. 题解 其他题解 ...

  5. 「题解报告」Blocks

    P3503 Blocks 题解 原题传送门 思路 首先我们可以发现,若 \(a_l\) ~ \(a_r\) 的平均值大于等于 \(k\) ,则这个区间一定可以转化为都大于等于 \(k\) 的.我们就把 ...

  6. 「题解报告」P3354

    P3354 题解 题目传送门 一道很恶心的树形dp 但是我喜欢 题目大意: 一片海旁边有一条树状的河,入海口有一个大伐木场,每条河的分叉处都有村庄.建了伐木场的村庄可以直接处理木料,否则要往下游的伐木 ...

  7. 「题解报告」CF1067A Array Without Local Maximums

    大佬们的题解都太深奥了,直接把转移方程放出来让其他大佬们感性理解,蒟蒻们很难理解,所以我就写了一篇让像我一样的蒟蒻能看懂的题解 原题传送门 动态规划三部曲:确定状态,转移方程,初始状态和答案. --神 ...

  8. P3167 [CQOI2014]通配符匹配

    吐槽 本来是去写AC自动机的,然后发现数据范围每个串100000,有100个串(???),连塞进trie树里都塞不进去,玩个鬼的AC自动机啊,tag不要乱打啊 最后拿字符串hash+爆搜一发搜过去了. ...

  9. 「题解报告」P7301 【[USACO21JAN] Spaced Out S】

    原题传送门 神奇的5分算法:直接输出样例. 20分算法 直接把每个点是否有牛的状态DFS一遍同时判断是否合法,时间复杂度约为\(O(2^{n^2})\)(因为有判断合法的剪枝所以会比这个低).而在前四 ...

随机推荐

  1. .NET中的 Count()、Count、Length 有什么不同

    更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年7月15日. Count().Count.Length,都用于获得序列长度或者说元素的个数,但它们有什么明确的区 ...

  2. dubbo的消费者是怎么获取提供者服务接口引用的?

    本文主要解读dubbo消费者是如何引用服务端接口的,是如何像本地调用一样调用远程服务的. 并试着从设计者的角度思考,为何这样设计. @Component public class DubboConsu ...

  3. Tensor的创建和维度的查看

    常见的Tensor创建方法 1,基础Tensor函数:torch.Tensor(2,2)32位浮点型 2,指定类型: torch.DoubleTensor(2,2)64位浮点型 3,使用python的 ...

  4. Ubuntu-apt-get出错

    ubuntu apt-get的时候出现: E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission ...

  5. react native 0.6x 在创建项目时,CocoaPods 的依赖安装步骤卡解决方案

    前言 你需要做两件事 gem换源 pod repo 换源 实战 如果你已经成功安装了CocoaPods.那么这里你需要卸载它.gem换源1. 卸载CocoaPods 查看gem安装的东西 gem li ...

  6. MySQL-1-概念

    数据库相关概念 DB:数据库(database):存储数据的"仓库".它保存了一系列有组织的数据 DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据 SQL: ...

  7. mariadb安装配置(主从配置)

    主服务器192.168.206.183 从服务器192.168.206.193 1.创建并编辑 /etc/yum.repos.d/MariaDB.repo文件(主从都要做) [mariadb] nam ...

  8. Linux从root切换某个用户时可能出现:-bash-4.1$

    Linux从root切换某个用户时可能出现:-bash-4.1$ 如下所示:[root@server ~]# su - postgres-bash-4.1$ id postgresuid=26(pos ...

  9. 生成RSA密钥的方法[转载]

    openssl genrsa -des3 -out privkey.pem 2048 这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码,如果你不想要每次都输入密码,可以改成(测试常 ...

  10. 5-21 拦截器 Interceptor

    Spring MVC拦截器 什么是拦截器 拦截器是SpringMvc框架提供的功能 它可以在控制器方法运行之前或运行之后(还有其它特殊时机)对请求进行处理或加工的特定接口 常见面试题:过滤器和拦截器的 ...