首页 > 其他分享 >【AcWing 3713】不同的子序列——动态规划(2019年南京大学考研机试题)

【AcWing 3713】不同的子序列——动态规划(2019年南京大学考研机试题)

时间:2023-09-02 16:44:17浏览次数:41  
标签:std 10 26 3713 int vector 2019 字符串 AcWing

给定一个字符串 \(S\) 和一个字符串 \(T\),请问共有多少个 \(S\) 的不同的子序列等于\(T\)。

输入格式
第一行包含整数 \(Q\),表示共有 \(Q\) 组测试数据。
每组数据第一行包含字符串 \(S\),第二行包含字符串 \(T\) 。

输出格式
每组数据输出一行,一个结果,由于结果可能很大,因此输出其对 \(1000000007\) 取模后的值。

数据范围
\(1≤Q≤50\)
\(1≤|S|,|T|≤10^4\)
保证 \(T\) 中的每个字符都是随机生成的。
字符串中只包含小写字母。

输入样例:

2
aaabbb
ab
njnunju
nju

输出样例:

9
5

解决方案

线性动态规划

本题如果数据量只有\(10^3\)的话就是一道常规的公共子序列的\(DP\)题。
常规解法
设\(f[i][j]\)表示\(s[1...i]\)中等于\(t[1...j]\)的子序列个数。对于\(s[i]\)有两种方案:与\(t[j]\)比较,或不与\(t[j]\)比较。
当\(s[i]\)不与\(t[j]\)进行比较时,\(f[i][j]\)从\((i-1,j)\)转移过来,\(f[i][j]=f[i - 1][j]\).
当\(s[i]\)与\(t[j]\)进行比较时,如果\(s[i] == t[j]\), \(f[i][j]\)就要加上在\(s[1...i-1]\)中等于\(t[1...j-1]\)的子序列个数,即$$f[i][j]=(f[i][j]+f[i-1][j-1])%MOD$$由于数据量为\(10^4\),观察到状态转移方程只用到了\(i-1\)的状态,因此可以像\(01\)背包一样用滚动数组优化,注意到要用\(f[i-1][j-1]\),因此内层循环需要倒序遍历

#include<bits/stdc++.h>

const int N = 10010, MOD = 1000000007; 

void solve(){
    std::string s, t;
    std::cin >> s >> t;
    int m = s.length(), n = t.length();
    std::vector<int> f(n + 5, 0);
    s = ' ' + s;
    t = ' ' + t;
    f[0] = 1;
    for(int i = 1; i <= m; i ++ ){
        for(int j = n; j >= 1; j -- ){
            if(s[i] == t[j]) f[j] = (f[j] + f[j - 1]) % MOD;
        }
    }
    std::cout << f[n] << '\n';
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    
    int q;
    std::cin >> q;
    
    while(q -- ){
        solve();
    }
    
    return 0;
}

时间复杂度: \(O(nmq)\) 超时
空间复杂度: \(O(n)\)

题目数据量为\(10^4\), 一次最多有\(50\)组数据,因此最坏情况下时间复杂度为\(5 \times 10^9\)。必定超时。需要优化。
参考链接:2019南京大学计算机考研复试机试题分享

要观察到两个点:1、只有在\(s[i]==t[j]\)时状态才发生转移2、字符串\(t\)中字符都是随机生成,说明\(t[j] == s[i]\)的概率为\(\frac{1}{26}\)。
因此我们可以首先预处理\(26\)个字母在\(t\)中出现的位置。在内层循环时,只从相同字符的位置处进行转移。

#pragma GCC optimize(2)

#include<bits/stdc++.h>

const int N = 10010, MOD = 1000000007;

void solve(){
    std::string s, t;
    std::cin >> s >> t;
    int m = s.length(), n = t.length();
    std::vector<int> f(n + 5, 0);
    std::vector<std::vector<int>> pos(26, std::vector<int>(n + 10, 0));
    std::vector<int> cnt(26);
    s = ' ' + s;
    t = ' ' + t;
    f[0] = 1;
    for(int i = 1; i <= n; i ++ ){
        int u = t[i] - 'a';
        cnt[u] ++ ;
        pos[u][cnt[u]] = i;
    }
    for(int i = 1; i <= m; i ++ ){
        int u = s[i] - 'a';
        for(int j = cnt[u]; j; j -- ){
            f[pos[u][j]] = (f[pos[u][j]] + f[pos[u][j] - 1]) % MOD;
        }
    }
    std::cout << f[n] << '\n';
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    
    int q;
    std::cin >> q;
    
    while(q -- ){
        solve();
    }
    
    return 0;
}

时间复杂度: \(O(\frac{nmq}{26})\)

标签:std,10,26,3713,int,vector,2019,字符串,AcWing
From: https://www.cnblogs.com/yjx-7355608/p/17673874.html

相关文章

  • BUUCTF [安洵杯 2019]easy_web
    试试模板注入发现,不行,然后伪协议,不行,再爆破目录也不行。从?img=TXpVek5UTTFNbVUzTURabE5qYz0入手,可能是base64编码。base64解码:(不知道为什么别的WP上变成这样了,否则解不出来)TXpVek5UTTFNbVUzTURabE5q得到:MzUzNTM1MmU3MDZlNj再base64解码:MzUzNTM1MmU3MDZl得到:353535......
  • BUUCTF [GWCTF 2019]我有一个数据库
    文件包含漏洞,和SQL注入等攻击方式一样,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含。有时......
  • AcWing - 闫氏DP分析法
    核心思想:从集合角度来分析DP问题在我们遇到的DP问题中,一般都是求在一个有限集内的最值,但是这些方案数量一般都是指数级别的,想要一个一个查找出来不太可能。所以DP方法是用来优化这种寻找最优方案的过程的。DP问题一般来说分析时都要经过两个阶段:状态表示(化零为整):指把一些具有......
  • BUUCTF [极客大挑战 2019]HardSQL
    判断过滤哪些关键词和字符报错注入报错注入在没法用union联合查询时用,但前提还是不能过滤一些关键的函数。报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。这里主要记录一下xpath语法错误和concat+rand()+group_by()导致主键重复xpa......
  • Acwing. 秋季每日一题
    Acwing.秋季每日一题活动链接A重复局面.国际象棋在对局时,同一局面连续或间断出现3次或3次以上,可由任意一方提出和棋。国际象棋每一个局面可以用大小为8×8的字符数组来表示,其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、马、兵分别用字母k、q、r、b、n、p......
  • BUUCTF [强网杯 2019]随便注
    判断传参方式,输入1'or1=1,URL传参,所以是get。报错error1064:YouhaveanerrorinyourSQLsyntax;checkthemanualthatcorrespondstoyourMariaDBserverversionfortherightsyntaxtousenear'''atline1报错说明后端参数后面有可能存在其他sql语句,我们......
  • vs2019-cuda配置入门
    cuda使用如下1、打开VS,新建C++空项目 2、右击源文件->添加->新建项 3、选择CUDAC/C++File,名称位main.cu 4、把下面的示例源码复制到main.cu中#include"cuda_runtime.h"#include"device_launch_parameters.h"#include<stdio.h>/***************************......
  • [极客大挑战 2019]PHP
    [极客大挑战2019]PHP打开链接,提示有备份网站的习惯![image-20230821164500785](../../../../../../Typora文章/[极客大挑战2019]PHP/image-20230821164500785.png)因此此时尝试访问一些常见的网站备份文件名,例如:常见网站源码备份文件后缀:tar.gz zip rar tar常见网站源......
  • Acwing. 第 118 场周赛
    Acwing.第118场周赛比赛链接这几天开学了,一直在宿舍歇着来着,从下周一开始就要开始加训了!!!A题循环串:给定两个整数n,a,请你用前a个小写字母为循环节,构成一个无限长的循环字符串,然后输出该字符串的前n个字符。例如,当a=2时,循环字符串为ababab...,当a=3时,循环字符串为......
  • AcWing 875. 快速幂
    题目给定$n$组$a_i,b_i,p_i$,对于每组数据,求出${a_i}^{b_i}mod{p_i}$的值。输入格式第一行包含整数$n$。接下来$n$行,每行包含三个整数$a_i,b_i,p_i$。输出格式对于每组数据,输出一个结果,表示${a_i}^{b_i}mod{p_i}$的值。每个结果占一行。数据范围$1≤n≤100000,......