题意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)题解的更多相关文章

  1. HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)

    题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. ...

  2. HDU 4632 Palindrome subsequence (区间DP)

    Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65535 K (Java/ ...

  3. HDU 4632 Palindrome subsequence (区间DP)

    题意 给定一个字符串,问有多少个回文子串(两个子串可以一样). 思路 注意到任意一个回文子序列收尾两个字符一定是相同的,于是可以区间dp,用dp[i][j]表示原字符串中[i,j]位置中出现的回文子序 ...

  4. HDU 4632 Palindrome subsequence (2013多校4 1001 DP)

    Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65535 K (Java/ ...

  5. HDU 4632 Palindrome subsequence(区间dp)

    Palindrome subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65535 K (Java/ ...

  6. HDU 4632 Palindrome subsequence(区间DP求回文子序列数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4632 题目大意:给你若干个字符串,回答每个字符串有多少个回文子序列(可以不连续的子串).解题思路: 设 ...

  7. hdu 4632 Palindrome subsequence

    http://acm.hdu.edu.cn/showproblem.php?pid=4632 简单DP 代码: #include<iostream> #include<cstdio& ...

  8. HDU 4632 Palindrome subsequence(DP)

    题目链接 做的我很无奈,当时思路很乱,慌乱之中,起了一个想法,可以做,但是需要优化.尼玛,思路跑偏了,自己挖个坑,封榜之后,才从坑里出来,过的队那么多,开始的时候过的那么快,应该就不是用这种扯淡方法做 ...

  9. 【HDU】4632 Palindrome subsequence(回文子串的个数)

    思路:设dp[i][j] 为i到j内回文子串的个数.先枚举所有字符串区间.再依据容斥原理. 那么状态转移方程为   dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+ ...

随机推荐

  1. scrapy 参考教程及安装

    scrapy 参考教程及安装环境: win7/10 64bit, python 3.6.x教程: http://python.jobbole.com/86405/安装过程0. 预先安装 VC14 64 ...

  2. SQL 中的连接查询

    关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...

  3. linux 查看python安装路径,版本号

    一.想要查看ubuntu中安装的python路径 方法一:whereis python     方法二:which python   二.想要查看ubuntu中安装的python版本号 python ...

  4. 这份书单,给那些想学Hadoop大数据、人工智能的人

    一.简单科普类 (文末附下载链接) 1.<人工智能:李开复谈AI如何重塑个人.商业与社会的未来图谱2> 作者:李开复,王咏刚 推荐理由:文章写得一般,但李开复和王永刚老师总结的还可以,算国 ...

  5. react+redux+react-router+node.js 开发实时聊天App 学习记录

    一.课程导学 1.React 主要解决的是UI层的问题,应用的状态需要借助Redux等状态管理. 2.前端React  +  antd-mobile UI组件库 + Redux 状态管理库 + Rea ...

  6. 使用SpringBoot的优势。

    Spring Boot 让开发变得更简单 Spring Boot 对开发效率的提升是全方位的,我们可以简单做一下对比: 在没有使用 Spring Boot 之前我们开发一个 web 项目需要做哪些工作 ...

  7. Promise的简单用法

    众所周知的,Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行.本特性带来的问题就是,一些将来的.未知的操作,必须异步实现.本文将讨论一个比较常见的异步解决方案— ...

  8. vue各种实例集合

    注意:以下所有示例基于vue 2.x.Vuex 2.x. vm.$mount()-挂载: <body> <div id="a"> </div> ...

  9. 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 ...

  10. git从安装到使用

    一.Git简介 Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制 ...