SDUT - Mountain Subsequences(dp)

题目链接:点击查看

题目大意:给出一个字符串 s ,问有多少个子序列严格满足山峰序列的约束,且子序列的长度大于等于三

题目分析:不难看出可以求出 dp1[ i ] 和 dp2[ i ] 分别代表的是点 i 前面严格递增子序列的数量和点 i 后面严格递减子序列的数量,这样枚举一遍令点 i 作为最高点,其贡献就是 dp1[ i ] * dp2[ i ] 之和了

现在问题转换为了如何求 dp1 和 dp2 ,因为有了字符串的约束,换句话说最多只有 26 个不同的字符,所以我们可以额外维护两个数组用来转移 dp1 和 dp2

设 num1[ i ][ j ] 和 num2[ i ][ j ] 分别代表的是,截止到 i 为止,以 j 为字符结尾的严格递增子序列有多少个,num1 记录的是从 1 ~ n 的状态,num2 记录的是从 n ~ 1 的状态,这样转移起来就比较简单了, 详细的看代码就足够了

代码:
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;

const int N=1e5+100;

const int mod=2012;

int a[N],dp1[N],dp2[N],num1[N][26],num2[N][26],n;

char s[N];

void init()
{
	memset(dp1,0,sizeof(dp1));
	memset(dp2,0,sizeof(dp2));
	memset(num1,0,sizeof(num1));
	memset(num2,0,sizeof(num2));
}
 
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	while(scanf("%d%s",&n,s+1)!=EOF)
	{
		init();
		for(int i=1;i<=n;i++)
			a[i]=s[i]-'a';
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<26;j++)
				num1[i][j]=num1[i-1][j];
			for(int j=0;j=1;i--)
		{
			for(int j=0;j<26;j++)
				num2[i][j]=num2[i+1][j];
			for(int j=0;j

 

你可能感兴趣的:(动态规划)