公共子序列_NOI导刊2011提高(03)题
这道题有点坑人啊~
首先,它需要取模,模数是100000000;(窝在这里死了好久好久,看了别人的代码才发现这一点)
然后我发现题解中没有序列自动机的方法,于是就来一发
首先,虽然序列自动机在定义上与后缀自动机、回文自动机等听起来比较高大上的算法同属于自动机的范畴,但它仅仅是个**普及-**算法
为何?因为你不学都有可能会(逃)
自动机,就是把一个字符串通过某种关系构成一幅有向无环图,这样可以方便我们进行图上dp
序列自动机的构造方法:
设一个字符集S,nxt[i][j]表示第i个位置往后第一个j元素出现的位置;
这个nxt数组可以O(n)的求出来,可以自行验证;
for(int i=n-;i>=;--i){
for(int j=;j<=;++j) nxt[i][j]=nxt[i+][j];
nxt[i][s[i+]-'a'+]=i+;
}
她能干什么事情呢?(应用)
1.判断是否是原字符串的子序列
当我们构造出nxt数组之后,可以贪心的寻找子序列;
2.求一个序列的子序列个数;(可以限定序列的长度)
我们在DAG上跑拓扑DP,f[v][j]表示从1~v寻找j个元素的方案数;
显然的:f[v][j]+=f[u][j-1];
#include <bits/stdc++.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
#define dec(i,a,b) for(register int i=a;i>=b;i--)
using namespace std;
char s[3010];
int nxt[3010][40];
int n,m;
long long f[3010][3010];
int rudu[3010];
const int p=998244353;
queue<int> qwq;
void tp()
{
qwq.push(0);
f[0][0]=1;
while(qwq.size()){
int u=qwq.front();
qwq.pop();
inc(i,0,25){
if(!nxt[u][i]) continue;
inc(j,0,u) f[nxt[u][i]][j+1]=(f[nxt[u][i]][j+1]+f[u][j])%p;
--rudu[nxt[u][i]];
if(rudu[nxt[u][i]]==0) qwq.push(nxt[u][i]);
}
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);cin>>m;
dec(i,n-1,0){
inc(j,0,25) nxt[i][j]=nxt[i+1][j];
nxt[i][s[i+1]-'a']=i+1;
inc(j,0,25) if(nxt[i][j]!=0) rudu[nxt[i][j]]++;
}
tp();
long long ans=0;
inc(i,1,n) ans=(ans+f[i][m])%p;
cout<<ans%p;
}
/*
addeade
3 aa
1
*/
#### 3.求两串的公共子序列个数(就是这道题)
#include <bits/stdc++.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
#define dec(i,a,b) for(register int i=a;i>=b;i--)
using namespace std;
char a[160],b[160],c[160];
int nxta[160][30],nxtb[160][30],nxtc[160][30];
long long f[160][160][160];
const int mod=100000000;
long long dfs(int x,int y,int z)
{
if(f[x][y][z]) return f[x][y][z];
inc(i,0,26){
if(nxta[x][i]&&nxtb[y][i]&&nxtc[z][i]){
f[x][y][z]=(f[x][y][z]+dfs(nxta[x][i],nxtb[y][i],nxtc[z][i]))%mod;
}
}
if(x||y||z) ++f[x][y][z];
return f[x][y][z]%mod;
}
int main()
{
int x,y,z;
int n;
cin>>n;
scanf("%s %s %s",a+1,b+1,c+1);
x=strlen(a+1); y=strlen(b+1); z=strlen(c+1);
dec(i,x-1,0){
inc(j,0,25) nxta[i][j]=nxta[i+1][j];
nxta[i][a[i+1]-'a']=i+1;
}
dec(i,y-1,0){
inc(j,0,25) nxtb[i][j]=nxtb[i+1][j];
nxtb[i][b[i+1]-'a']=i+1;
}
dec(i,z-1,0){
inc(j,0,25) nxtc[i][j]=nxtc[i+1][j];
nxtc[i][c[i+1]-'a']=i+1;
}
cout<<dfs(0,0,0)%mod;
}
4.求字符串的回文子序列个数
首先原串与反串都建一遍;
就相当于从左右端点向中间跑自动机;
显然:x+y<=n+1才会合法;
但要注意,我们只能统计偶数长度的字符串,而不能统计奇数个数的字符串;
因为我们永远都是两个两个地串;
long long Dfs(int x,int y){
if(f[x][y]) return f[x][y];
for(int i=1;i<=a;++i)
if(nxt1[x][i]&&nxt2[y][i]){
if(nxt1[x][i]+nxt2[y][i]>n+1) continue;
if(nxt1[x][i]+nxt2[y][i]<n+1) f[x][y]++;
f[x][y]=(f[x][y]+Dfs(nxt1[x][i],nxt2[y][i]))%mod;
}
return ++f[x][y];
}
公共子序列_NOI导刊2011提高(03)题的更多相关文章
- P1836 【数页码_NOI导刊2011提高(04)】
P1836 数页码_NOI导刊2011提高(04) 题目描述 一本书的页码是从1—n编号的连续整数:1,2,3,…,n.请你求出全部页码中所有单个数字的和,例如第123页,它的和就是1+2+3=6. ...
- 贪心—— P1809 过河问题_NOI导刊2011提高(01)
洛谷——P1809 过河问题_NOI导刊2011提高(01) 题目描述 有一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸.而东岸边有一条小船. 船太小了,一次只能 ...
- 洛谷 P1808 单词分类_NOI导刊2011提高(01)
P1808 单词分类_NOI导刊2011提高(01) 题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且仅当 ...
- 洛谷P1808 单词分类_NOI导刊2011提高(01) 字符串排序
洛谷P1808 单词分类_NOI导刊2011提高(01) 题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且 ...
- P1835 素数密度_NOI导刊2011提高(04)
题目描述 给定区间[L,R](L≤R≤2147483647,R-L≤1000000),请计算区间中素数的个数. 输入输出格式 输入格式: 两个数L和R. 输出格式: 一行,区间中素数的个数. 输入输出 ...
- 单人纸牌_NOI导刊2011提高(04)
单人纸牌 时间限制: 1 Sec 内存限制: 128 MB 题目描述 单人纸牌游戏,共 36 张牌分成 9 叠,每叠 4 张牌面向上.每次,游戏者可以从某两个不同的牌堆最顶上取出两张牌面相同的牌(如 ...
- 素数密度_NOI导刊2011提高(04)
题目描述 给定区间[L, R](L <= R <= 2147483647,R-L <= 1000000),请计算区间中素数的个数. 输入 两个数 L 和 R. 输出 一行,区间中素数 ...
- P1837 单人纸牌_NOI导刊2011提高(04)
题目描述 单人纸牌游戏,共36张牌分成9叠,每叠4张牌面向上.每次,游戏者可以从某两个不同的牌堆最顶上取出两张牌面相同的牌(如黑桃10和梅花10)并且一起拿走.如果最后所有纸牌都被取走,则游戏者就赢了 ...
- 洛谷P1809 过河问题_NOI导刊2011提高(01)
To 洛谷.1809 过河问题 题目描述 有一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸.而东岸边有一条小船. 船太小了,一次只能乘坐两人.每个人都有一个渡河时 ...
随机推荐
- maven项目创建2
添加依赖索引 但是默认是没有索引的,要手动创建索引 依赖范围 debug 配置 运行常见问题 处理办法,JDK重新安装 网络添加依赖网站
- idea中JSP页面不能访问静态资源(图片,js,css)
必须配置SpringMvc对访问静态资源的支持,idea默认就是在main/webapp 下的文件路径,要在web-info同级的resource文件下放置,JSP中 ${pageContext.re ...
- Springboot(九).多文件上传下载文件(并将url存入数据库表中)
一. 文件上传 这里我们使用request.getSession().getServletContext().getRealPath("/static")的方式来设置文件的存储 ...
- XFF和referer
XFF构造来源IP Refer构造来源浏览器
- [CSP-S模拟测试]:统计(树状数组+乱搞)
题目传送门(内部题120) 输入格式 第一行,两个正整数$n,m$. 第二行,$n$个正整数$a_1,a_2,...,a_n$,保证$1\leqslant a_i\leqslant n$,可能存在相同 ...
- linux pwd指令的C实现
linux pwd指令的C实现 pwd指令的功能介绍 linux pwd命令用于显示工作目录 执行pwd命令可立刻得知当前所在工作目录的绝对路径名称. 示例: 查询系统手册 如图所示,getcwd的描 ...
- 设置Apache监听多个端口
1.在配置文件httpd.conf中Listen多个端口 Listen localhost:8033 Listen localhost:8083 ....... 2.在配置文件夹下的extra文 ...
- 使用C#语言,将DataTable 转换成域模型
DataTable dt = SqlHelper.Query(strQuery); ) * size).Take(pagesize); List<Model> listData = new ...
- JSP——隐式对象(implicit object)
Servlet容器将几个对象传递给它所运行的Servlet. 例如,在Servlet的service方法中获得HttpServletRequest和HttpServletResponse,并在init ...
- App架构设计:接口的设计
安全机制的设计 现在,大部分App的接口都采用RESTful架构,RESTFul最重要的一个设计原则就是,客户端与服务器的交互在请求之间是无状态的,也就是说,当涉及到用户状态时,每次请求都要带上身份验 ...