雅礼集训【Day6-1】字符串

假设我们有串\(a\),我们设\(a'\)为\(a\)翻转后按为取反过后的串。

我们只考虑前一半的,长为\(m\)的串。如果前半截匹配了\(a\)或者\(a'\),则\(a\)就被匹配上了。所以我们记\(f_{i,j,S}\)表示长度\(i\),在AC自动机上匹配到了\(j\)节点,已经匹配了的串的集合为\(S\)的方案数。

但是可能会出现\(a\)出现的位置跨越了\(m\),这样我们就会出问题。因为我们记录了生成的串在AC自动机上匹配的节点,所以我们就能得到\(a\)在前半截中匹配的长度。如果这个长度\(\geq\lfloor \frac{len}{2}\rfloor\),则我们能知道后半截是什么,也就能判断是否合法了。

那如果\(a\)没有匹配长度\(\geq\lfloor \frac{len}{2}\rfloor\)的情况呢?我们发现,此时\(a'\)的匹配长度一定\(\geq\lfloor \frac{len}{2}\rfloor\),所以我们同时判断\(a\)和\(a'\),其中一个成立就行了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 2005
#define M 505 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} const ll mod=998244353;
int n,m;
string str[20];
struct trie {
int ch[2];
int w;
int fail;
int flag;
int len;
}tr[N]; int rt=1;
int cnt=1;
void Insert(string s,int id) {
int len=s.length();
int v=1;
for(int i=0;i<len;i++) {
int j=s[i]-'0';
if(!tr[v].ch[j]) {
tr[v].ch[j]=++cnt;
tr[tr[v].ch[j]].len=tr[v].len+1;
}
v=tr[v].ch[j];
}
tr[v].w|=1<<id-1;
} queue<int>q;
void build_fail() {
for(int i=0;i<2;i++) {
if(!tr[1].ch[i]) tr[1].ch[i]=1;
else {
int x=tr[1].ch[i];
tr[x].fail=1;
q.push(x);
}
}
while(!q.empty()) {
int v=q.front();
q.pop();
tr[v].w|=tr[tr[v].fail].w;
for(int i=0;i<2;i++) {
if(!tr[v].ch[i]) tr[v].ch[i]=tr[tr[v].fail].ch[i];
else {
int sn=tr[v].ch[i];
int f=tr[v].fail;
tr[sn].fail=tr[f].ch[i];
q.push(sn);
}
}
}
}
int pre[20][N];
int f[M][1205][1<<6];
bool pd(string &a,int len,int v,int id) {
int now=1;
tr[1].flag=1;
for(int i=0;i<len;i++) {
now=tr[now].ch[a[i]-'0'];
tr[now].flag=1;
}
while(!tr[v].flag) v=tr[v].fail;
int nlen=0;
now=1;
for(int i=0;i<len&&now!=v;i++,nlen++) {
now=tr[now].ch[a[i]-'0'];
}
int flag=0;
while(v) {
if(tr[v].flag&&pre[id][tr[v].len]) flag=1;
v=tr[v].fail;
}
tr[1].flag=0;
now=1;
for(int i=0;i<len;i++) {
now=tr[now].ch[a[i]-'0'];
tr[now].flag=0;
}
return flag;
} bool chk(int v,int S) {
for(int i=1;i<=n;i++) {
if(S>>i-1&1) continue ;
int len=str[i].length();
if(!pd(str[i],len,v,i)&&!pd(str[i+n],len,v,i+n)) return 0;
}
return 1;
} int main() {
n=Get(),m=Get();
for(int i=1;i<=n;i++) cin>>str[i];
for(int i=1;i<=n;i++) {
int len=str[i].length();
for(int j=len-1;j>=0;j--) {
str[i+n].push_back(str[i][j]^1);
}
}
for(int i=1;i<=n;i++) {
Insert(str[i],i);
Insert(str[i+n],i);
}
build_fail();
f[0][1][0]=1;
for(int i=0;i<m;i++) {
for(int j=1;j<=cnt;j++) {
for(int S=0;S<1<<n;S++) {
if(!f[i][j][S]) continue ;
for(int k=0;k<2;k++) {
int to=tr[j].ch[k];
(f[i+1][to][S|tr[to].w]+=f[i][j][S])%=mod;
}
}
}
} for(int i=1;i<=2*n;i++) {
int len=str[i].length();
for(int st=1;st<=len;st++) {
if(st*2<len) continue ;
int flag=1;
for(int j=st;j<len;j++) {
if(str[i][j]==str[i][2*st-j-1]) flag=0;
}
pre[i][st]=flag;
}
} int ans=0;
for(int i=1;i<=cnt;i++) {
for(int S=0;S<1<<n;S++) {
if(!f[m][i][S]) continue ;
if(chk(i,S)) {
(ans+=f[m][i][S])%=mod;
}
}
}
cout<<ans;
return 0;
}

雅礼集训【Day6-1】字符串的更多相关文章

  1. 雅礼集训 Day6 T2 Equation 解题报告

    Equation 题目描述 有一棵\(n\)个点的以\(1\)为根的树,以及\(n\)个整数变量\(x_i\).树上\(i\)的父亲是\(f_i\),每条边\((i,f_i)\)有一个权值\(w_i\ ...

  2. 雅礼集训 Day6 T1 Merchant 解题报告

    Merchant 题目描述 有\(n\)个物品,第\(i\)个物品有两个属性\(k_i,b_i\),表示它在时刻\(x\)的价值为\(k_i\times x+b_i\). 当前处于时刻\(0\),你可 ...

  3. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  4. 「雅礼集训 2017 Day7」事情的相似度

    「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...

  5. 雅礼集训1-9day爆零记

    雅礼集训1-9day爆零记 先膜一下虐爆我的JEFF巨佬 Day0 我也不知道我要去干嘛,就不想搞文化科 (文化太辣鸡了.jpg) 听李总说可以去看(羡慕)各路大佬谈笑风声,我就报一个名吧,没想到还真 ...

  6. LOJ_6045_「雅礼集训 2017 Day8」价 _最小割

    LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...

  7. 「雅礼集训 2017 Day2」解题报告

    「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...

  8. 「雅礼集训 2017 Day1」 解题报告

    「雅礼集训 2017 Day1」市场 挺神仙的一题.涉及区间加.区间除.区间最小值和区间和.虽然标算就是暴力,但是复杂度是有保证的. 我们知道如果线段树上的一个结点,\(max=min\) 或者 \( ...

  9. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

随机推荐

  1. vs2010打不开vs2017的.sln文件,出现错误提示 “选择的文件是解决方案文件 但是用此应用程序的较新版本创建的,无法打开”

    解决方案: 1.复制下面这段语句 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 2. ...

  2. python基础学习(三)变量和类型

    变量的作用:变量就是用来存储数据的. 变量的定义 在python中,变量在使用之前需要进行赋值,变量只有赋值后才能使用,如果变量没有赋值就使用会出现什么情况呢?如下图,使用之前变量未定义,会报错,如下 ...

  3. Mybatis框架可视化(1)

    Mybatis整体架构视图: 接 口 层 SqlSession (定义了Mybatis暴露给应用程序调用的API) 核 心 处 理 层 配置解析 (加载核心配置.映射配置. mapper接口注解信息, ...

  4. ACM ICPC 2017 Warmup Contest 9 I

    I. Older Brother Your older brother is an amateur mathematician with lots of experience. However, hi ...

  5. PHP常用函数归类【持续整理中......】

    一.PHP基础语法   变量,常量     严格区分大小写,但内置结构或关键字无所谓(echo)     命名:不能以数字,空格,.来开头,但是可以有汉字,eg:$变量="aa"; ...

  6. Session的原理,大型网站中Session方面应注意什么?

    一.Session和Cookie的区别Session是在服务器端保持会话数据的一种方法(通常用于pc端网站保持登录状态,手机端通常会使用token方式实现),存储在服务端. Cookie是在客户端保持 ...

  7. 洛谷P2470 [SCOI2007]压缩(区间dp)

    题意 题目链接 Sol 神仙题Orz 考虑区间dp,如果我们只设\(f[l][r]\)表示\(s_{lr}\)被压缩的最小长度,而不去关心内部\(M\)分布的话,可能在转移的时候转移出非法状态 因此考 ...

  8. Native SBS for Android

    Native SBS for Android是一款非常棒的软件,支持安卓在2D界面下左右分屏显示,并可以设置缩放比例及左右间距,横屏自动切换为左右分屏显示模式,竖屏则为正常显示.启动左右分屏模式后,将 ...

  9. java8中Lambda表达式和Stream API

    一.Lambda表达式 1.语法格式 Lambda是匿名函数,可以传递代码.使用“->”操作符,改操作符将lambda分成两部分: 左侧:指定了 Lambda 表达式需要的所有参数 右侧:指定了 ...

  10. <自动化测试方案_5>第五章、代码单元自动化测试

    第五章.代码单元自动化测试 代码单元测试需要根据编程语言,选择单元测试框架,然后访问类方法,函数.代码单元测试做自动化,相比API.UI自动化做起来更加麻烦,建议放到待API自动化测试.UI自动化测试 ...