HDU 4632 Palindrome subsequence & FJUT3681 回文子序列种类数(回文子序列个数/回文子序列种数 容斥 + 区间DP)题解
题意1:问你一个串有几个不连续子序列(相同字母不同位置视为两个)
题意2:问你一个串有几种不连续子序列(相同字母不同位置视为一个,空串视为一个子序列)
思路1:由容斥可知当两个边界字母相同时 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1;当两个字母不同时 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]。然后区间DP即可
思路2:由思路1我们能大致知道怎么做,显然两边界字母不一样时情况是一样的。当两边字母一样时,那么就要判断中间的重复情况。
我们设l和r,表示i + 1 ~ j - 1里最左边的s[i]字母和最右边的s[i]字母
当 l == r 那么就只有一个相同字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1,答案为中间部分 + 中间加上两边界 + s[i]s[j]串
当 l > r,没有这个字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] + 2,答案为中间部分 + 中间加上两边界 + s[i]s[j]串 + s[i]
当l < r,说明至少有两个字母,dp[i][j] = dp[i + 1][j - 1] + dp[i + 1][j - 1] - dp[l + 1][r - 1],答案为中间部分 + 中间加上两边界 - (l,r)区间内种数,因为这里面的和s[l],s[r]组成的串和s[i],s[j]重复
代码1:
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 1e3 + ;
const ll MOD = 1e4 + ;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxn]; //i到j种数
char s[maxn];
int main(){
int t, ca = ;
scanf("%d", &t);
while(t--){
scanf("%s", s + );
int n = strlen(s + );
for(int i = ; i <= n; i++){
dp[i][i] = ;
}
for(int len = ; len <= n; len++){
for(int i = ; i + len - <= n; i++){
int j = i + len - ;
if(s[i] == s[j]){
dp[i][j] = dp[i + ][j] + dp[i][j - ] + ;
}
else{
dp[i][j] = dp[i + ][j] + dp[i][j - ] - dp[i + ][j - ];
}
dp[i][j] = (dp[i][j] + MOD) % MOD;
}
}
printf("Case %d: %d\n", ca++, dp[][n]);
}
return ;
}
代码2:
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 1e3 + ;
const ll MOD = 1e9 + ;
const int INF = 0x3f3f3f3f;
ll dp[maxn][maxn]; //i到j种数
char s[maxn];
int main(){
int t, ca = , n;
scanf("%d", &t);
while(t--){
scanf("%s", s + );
int n = strlen(s + );
for(int i = ; i <= n; i++){
dp[i][i] = ;
}
for(int len = ; len <= n; len++){
for(int i = ; i + len - <= n; i++){
int j = i + len - ;
if(s[i] == s[j]){
int l = i + , r = j - ;
while(s[l] != s[i] && l <= r) l++;
while(s[r] != s[i] && l <= r) r--;
if(l > r){
dp[i][j] = dp[i + ][j - ] + dp[i + ][j - ] + ;
}
else if(l == r){
dp[i][j] = dp[i + ][j - ] + dp[i + ][j - ] + ;
}
else{
dp[i][j] = dp[i + ][j - ] + dp[i + ][j - ] - dp[l + ][r - ];
}
}
else{
dp[i][j] = dp[i + ][j] + dp[i][j - ] - dp[i + ][j - ];
}
}
}
printf("Case %d: %lld\n", ca++, dp[][n]);
}
return ;
}
HDU 4632 Palindrome subsequence & FJUT3681 回文子序列种类数(回文子序列个数/回文子序列种数 容斥 + 区间DP)题解的更多相关文章
- HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)
题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. ...
- HDU 4632 Palindrome subsequence (区间DP)
Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65535 K (Java/ ...
- HDU 4632 Palindrome subsequence (区间DP)
题意 给定一个字符串,问有多少个回文子串(两个子串可以一样). 思路 注意到任意一个回文子序列收尾两个字符一定是相同的,于是可以区间dp,用dp[i][j]表示原字符串中[i,j]位置中出现的回文子序 ...
- HDU 4632 Palindrome subsequence (2013多校4 1001 DP)
Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65535 K (Java/ ...
- HDU 4632 Palindrome subsequence(区间dp)
Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65535 K (Java/ ...
- HDU 4632 Palindrome subsequence(区间DP求回文子序列数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4632 题目大意:给你若干个字符串,回答每个字符串有多少个回文子序列(可以不连续的子串).解题思路: 设 ...
- hdu 4632 Palindrome subsequence
http://acm.hdu.edu.cn/showproblem.php?pid=4632 简单DP 代码: #include<iostream> #include<cstdio& ...
- HDU 4632 Palindrome subsequence(DP)
题目链接 做的我很无奈,当时思路很乱,慌乱之中,起了一个想法,可以做,但是需要优化.尼玛,思路跑偏了,自己挖个坑,封榜之后,才从坑里出来,过的队那么多,开始的时候过的那么快,应该就不是用这种扯淡方法做 ...
- 【HDU】4632 Palindrome subsequence(回文子串的个数)
思路:设dp[i][j] 为i到j内回文子串的个数.先枚举所有字符串区间.再依据容斥原理. 那么状态转移方程为 dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+ ...
随机推荐
- scrapy 参考教程及安装
scrapy 参考教程及安装环境: win7/10 64bit, python 3.6.x教程: http://python.jobbole.com/86405/安装过程0. 预先安装 VC14 64 ...
- SQL 中的连接查询
关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...
- linux 查看python安装路径,版本号
一.想要查看ubuntu中安装的python路径 方法一:whereis python 方法二:which python 二.想要查看ubuntu中安装的python版本号 python ...
- 这份书单,给那些想学Hadoop大数据、人工智能的人
一.简单科普类 (文末附下载链接) 1.<人工智能:李开复谈AI如何重塑个人.商业与社会的未来图谱2> 作者:李开复,王咏刚 推荐理由:文章写得一般,但李开复和王永刚老师总结的还可以,算国 ...
- react+redux+react-router+node.js 开发实时聊天App 学习记录
一.课程导学 1.React 主要解决的是UI层的问题,应用的状态需要借助Redux等状态管理. 2.前端React + antd-mobile UI组件库 + Redux 状态管理库 + Rea ...
- 使用SpringBoot的优势。
Spring Boot 让开发变得更简单 Spring Boot 对开发效率的提升是全方位的,我们可以简单做一下对比: 在没有使用 Spring Boot 之前我们开发一个 web 项目需要做哪些工作 ...
- Promise的简单用法
众所周知的,Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行.本特性带来的问题就是,一些将来的.未知的操作,必须异步实现.本文将讨论一个比较常见的异步解决方案— ...
- vue各种实例集合
注意:以下所有示例基于vue 2.x.Vuex 2.x. vm.$mount()-挂载: <body> <div id="a"> </div> ...
- Icarscan VCI is definitely the update variation of Start iDiag
Start iCarScan is alternative of Super X431 iDiag, it’ll make your Android smartphone or tablet righ ...
- git从安装到使用
一.Git简介 Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制 ...