Nowcoder Removal ( 字符串上的线性 DP )
题意 : 给出长度为 n 的字符串、问你准确删除 m 个元素之后、能产生多少种不同的子串
分析 ( 参考博客 ):
可以考虑线性 DP 解决这个问题
试着如下定义动态规划数组
dp[i][j] = 在加入第 i 个字符串后、总共删除了 j 个字符后的不同子串的个数
不难写出状态转移方程 dp[i][j] = dp[i-1][j] + dp[i-1][j-1]
代表在 i 这个字符加入之后、在删除总次数为 j 的情况下是否删除 i 的两个状态转移而来
但是这样子势必会有重复的字串出现、例如 aaa 这个字符串 删除第一个和第二个都产生 aa
所以需要减去重复的部分、注意到如果在第 i 个字符之前后一个和它相同的字符出现记做 pre_i
而且满足 (i字符位置) - (pre_i字符位置) <= j 则说明会有重复计算的情况
因为如果在总共删除的 j 个字符中包含了pre_i ~ i 之间的字符、那么便会产生重复
例如 abcexxe 发现有一前一后两个 e 两个之间相隔有两个 x
那么如果用上述的转移方程去更新的话 dp[4][0] = "abce" 且 dp[7][3] = 包含了 "abce"
所以会有诸如这样子的重复、减去就行了
怎么减? if (i字符位置) - (pre_i字符位置) <= j 执行 dp[i][j] -= dp[ pre_i - 1 ][ j - ( i - pre_i ) ]
因为先前重复计算的部分就包含了 pre_i 位置下减去了 j - ( i - pre_i ) 个字符的部分
#include<bits/stdc++.h> #define LL __int64 #define ULL unsigned long long #define scl(i) scanf("%lld", &i) #define scll(i, j) scanf("%lld %lld", &i, &j) #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k) #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l) #define scs(i) scanf("%s", i) #define sci(i) scanf("%d", &i) #define scd(i) scanf("%lf", &i) #define scIl(i) scanf("%I64d", &i) #define scii(i, j) scanf("%d %d", &i, &j) #define scdd(i, j) scanf("%lf %lf", &i, &j) #define scIll(i, j) scanf("%I64d %I64d", &i, &j) #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k) #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k) #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k) #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l) #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l) #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l) #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define lowbit(i) (i & (-i)) #define mem(i, j) memset(i, j, sizeof(i)) #define fir first #define sec second #define VI vector<int> #define ins(i) insert(i) #define pb(i) push_back(i) #define pii pair<int, int> #define VL vector<long long> #define mk(i, j) make_pair(i, j) #define all(i) i.begin(), i.end() #define pll pair<long long, long long> #define _TIME 0 #define _INPUT 0 #define _OUTPUT 0 clock_t START, END; void __stTIME(); void __enTIME(); void __IOPUT(); using namespace std; ; ; int arr[maxn]; int Pre[maxn]; + ]; + ]; int main(void){__stTIME();__IOPUT(); int n, m, k; while(~sciii(n, m, k)){ ; i<=n; i++) Last[i] = ; ; i<=n; i++){ sci(arr[i]); Pre[i] = Last[arr[i]]; Last[arr[i]] = i; } ; i<=m; i++) dp[i][i] = ; ///代表空串、在下面的转移方程中 dp[i-1][j] 会用到 ///其意义是更新到 i 为止在不删除第 i 个字符情况下总共删除了 j 个 ///字符的情况、此时就说明只剩下第 i 个字符、dp数值应该为 1 ///故给空串赋值为 1 ; i<=n; i++){ dp[i][] = ; ; j<=min(m, i-); j++){ dp[i][j] = (dp[i-][j-]%mod + dp[i-][j]%mod) % mod; if(Pre[i] && i - Pre[i] <= j){ dp[i][j] = (dp[i][j] - dp[ Pre[i] - ][ j - (i - Pre[i]) ] + mod ) % mod; } } } printf("%d\n", dp[n][m]%mod); } __enTIME();;} void __stTIME() { #if _TIME START = clock(); #endif } void __enTIME() { #if _TIME END = clock(); cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl; #endif } void __IOPUT() { #if _INPUT freopen("in.txt", "r", stdin); #endif #if _OUTPUT freopen("out.txt", "w", stdout); #endif }
Nowcoder Removal ( 字符串上的线性 DP )的更多相关文章
- Codeforces 176B (线性DP+字符串)
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...
- 动态规划——线性dp
我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...
- 动态规划_线性dp
https://www.cnblogs.com/31415926535x/p/10415694.html 线性dp是很基础的一种动态规划,,经典题和他的变种有很多,比如两个串的LCS,LIS,最大子序 ...
- 线性DP详解
顾名思义,线性DP就是在一条线上进行DP,这里举一些典型的例子. LIS问题(最长上升子序列问题) 题目 给定一个长度为N的序列A,求最长的数值单调递增的子序列的长度. 上升子序列B可表示为B={Ak ...
- 洛谷P1140 相似基因(线性DP)
题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了444种核苷酸,简记作A,C,G,TA,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类 ...
- LightOJ1044 Palindrome Partitioning(区间DP+线性DP)
问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...
- hdu1712 线性dp
//Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...
- 『最大M子段和 线性DP』
最大M子段和(51nod 1052) Description N个整数组成的序列a[1],a[2],a[3],-,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M &g ...
- poj2228 Naptime【(环结构)线性DP】
Naptime Time Limit: 1000MS Memory Limit: 65536K Total Submissions:3374 Accepted: 1281 Descriptio ...
随机推荐
- 基于rabbitmq的Spring-amqp基本使用
目录 1. 依赖和配置 添加AMQP的启动器: 在application.yml中添加RabbitMQ地址: 2. 监听者 3. AmqpTemplate 4. 测试代码 Spring-amqp是对A ...
- 04: gitlab安装与使用
1.1 gitlab安装(192.168.56.12中安装) 1.GitLab是什么? 1. GitLab实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. 2. GitLa ...
- linux基础命令<二>
1.关机 init 0 poweroff halt shutdown –h now 2.重启 init 6 reboot shutdown –r now 3.查询都有那些用户在系统 ...
- Collection接口的子接口——Queue接口
https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html public interface Queue<E> exten ...
- oracle查看执行计划以及使用场景
文档结构: oracle执行计划使用场景 环境: Centos 6.10 Oracle 18.3.0.0.0 c 11g默认启动了自动统计信息收集的任务,默认运行时间是周一到周五晚上10点和周6,周天 ...
- 如何同步多个 git 远程仓库
请看 -> 如何同步多个 git 远程仓库
- LintCode 29---交叉字符串
public class Solution { /** * @param s1: A string * @param s2: A string * @param s3: A string * @ret ...
- 转载:Linux目录文件的权限查看与修改
######################################## ...
- python删除数组中元素
有数组a,要求去掉a所有为0的元素 a = [2,4,0,8,9,10,100,0,9,7] Filter a= filter(None, a) Lambada a = filter(lambda x ...
- IT经理工作职责
IT经理工作职责: 1. 管理公司信息技术以及计算机系统. 2. 确保公司信息技术是可访问的并且配备了现有的可用的硬件和软件. 3. 监控并且维护公司信息技术并确保能够得到最大化的使用 ...