uva live 3516 Exploring Pyramids 区间DP

//	uva live 3516 Exploring Pyramids 区间DP
//
//	题目大意:
//
//		给你一个多叉树,每个节点是一个大写字母,从根节点走,按照先序遍历的
//	原则访问,不能访问则回溯,每次记录一下节点的字符,最后得到一个字符串.现
//	在给你一个字符串,问可能符合条件的多叉树的数量.
//
//	解题思路:
//
//		区间DP,我们注意到,从根节点出发,一定会再次回到根节点,那么我们可以设
//	d(i,j) 是序列i到j段形成的符合条件的多叉树的数量,则
//	i~j一定会有一个k使得s[i] = s[k]{因为一定要回到i}.所以问题就转化为i+1~k-1
//	的子树和k~j树中的另外一个部分.这两部分乘积的结果就是区间的答案.采用记忆化
//	搜索.用vis标记是否访问过.边界为d(i,i) = 1,s[i]!=s[j]时,d(i,j)=0,不要忘记
//	要回到根如果头和尾不相等,肯定回不去的.
//
//	感悟:
//
//		区间DP我知道,状态我想的到,但是状态的转移,不是非常清楚明白.继续加油吧~~~
//	FIGHTING!!!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

typedef long long ll;
const int MAX_N = 308;
const int MOD = 1000000000;

int n;

char s[MAX_N];
ll d[MAX_N][MAX_N];
bool vis[MAX_N][MAX_N];

ll dp(int x,int y){
	if (x > y)
		return d[x][y] = 0;
	if (x == y)
		return d[x][y] = 1;
	if (s[x]!=s[y])
		return 0;
	if (vis[x][y])
		return d[x][y];

	vis[x][y] = 1;

	ll& ans = d[x][y];

	ans = 0;

	for (int k=x+2;k<=y;k++){ // 注意,这里最少走两步,走一步就是自己到自己
		if (s[x] == s[k])
			ans = (ans + dp(x+1,k-1)%MOD * dp(k,y))%MOD;
	}
	return ans % MOD;

}

void solve(){
	memset(d,0,sizeof(d));
	memset(vis,0,sizeof(vis));
	printf("%lld\n",dp(0,strlen(s)-1));
}

int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%s",s)!=EOF){
		solve();
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 11:08:07

uva live 3516 Exploring Pyramids 区间DP的相关文章

UVALive 3516 Exploring Pyramids 区间dp+计数原理

题目链接:点击打开链接 给定多叉树的先序遍历结果,求多叉树的同构数 思路:区间dp import java.io.PrintWriter; import java.util.ArrayList; import java.util.Scanner; public class Main { int min(int a,int b){return a>b?b:a;} int max(int a,int b){return a>b?a:b;} long min(long a,long b){retur

UVALive 3516 Exploring Pyramids (区间dp)

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define ll long long const int maxn = 310; const ll mod = 1e9; char s[maxn]; ll dp[maxn][maxn]; ll solve(int i, int j) { if(i == j) retu

UVA 1362 Exploring Pyramids 区间DP

Archaeologists have discovered a new set of hidden caves in one of the Egyptian pyramids. The decryption of ancient hieroglyphs on the walls nearby showed that the caves structure is as follows. There are n caves in a pyramid, connected by narrow pas

uva 10529 - Dumb Bones(概率+区间dp)

题目连接:uva 10529 - Dumb Bones 题目大意:给定n,表示要放n个骨牌,每次放下骨牌,有可能向左倒的概率为pl,向右倒的概率为pr,如果倒下,会将那一侧的骨牌全部推倒,可以选择位置先后放骨牌,问说一种放骨牌次数最少的期望是多少. 解题思路:dp[i]表示放i个骨牌需要的步数期望,维护一个最优放的位置,dp[i] = min\{ (从i-1到i的步数)} + (0到i-1的步数)} (从i-1到i的步数):dp[i?j?1]?pl+dp[j]?pr+11?pl?pr (0到i-

uva 10003 Cutting Sticks 简单区间dp

// uva 10003 Cutting Sticks 区间dp // 经典的区间dp // dp(i,j)表示切割小木棍i-j所需要的最小花费 // 则状态转移为dp(i,j) = min{dp(i,k) + dp(k,j) + a[j]-a[i]) // 其中k>i && k<j // a[j] - a[i] 为第一刀切割的代价 // a[0] = 0,a[n+1] = L; // dp数组初始化的时候dp[i][i+1]的值为 0,这表示 // 每一段都已经是切割了的,不

uva 10003 Cutting Sticks 【区间dp】

题目:uva 10003 Cutting Sticks 题意:给出一根长度 l 的木棍,要截断从某些点,然后截断的花费是当前木棍的长度,求总的最小花费? 分析:典型的区间dp,其实和石子归并是一样的,花费就是石子的和,那么久不用多说了. AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include <map> #include <

UVA 10891 Game of Sum 区间dp

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461 题目意思大致是给你一串数字,A,B两个人轮流从两端取一段数字并得到该串数字的和的点数,每个人都尽可能的多的点数,问A最多能比B多多少点. 区间dp,一开始打算分AB,但是发现太麻烦了,最后用dp(l,r)表示在区间l~r中先手能赢的的最多点数.假设A是区间(l,r)的先手的话,如果A选择了(l,k )// 或(k+1,r)的数字,那他的得分(l,r)的总分减去B在余

【区间dp】【记忆化搜索】UVALive - 3516 - Exploring Pyramids

f(i,j)=sum(f(i+1,k-1)*f(k,j) | i+2<=k<=j,Si=Sk=Sj). f(i+1,k-1)是划分出第一颗子树,f(k,j)是划分出剩下的子树. #include<cstdio> #include<cstring> using namespace std; typedef long long ll; #define MOD 1000000000ll char s[310]; ll f[310][310]; int n; ll dp(int

UVa 1362(LA 3516) Exploring Pyramids

依旧是<训练指南>上的一道例题.思路大致相同,即设有一个序列S(i),S(i+1),S(i+2)...S(j),d[i,j]为所求的解.当S(i)==S(k),i<k<=j 时,说明在k回到根,那么S(i+1)...S(k-1)构成一棵独立的子树(当然也可能并不是子树).那么d[i,j]就要加上d[i+1,k-1]*d[k,j],不断递增k,每遇到一个k,d[i,j]+=d[i+1,k-1]*d[k,j]直到k>j.最后的d[i,j]就是序列S(i)..S(j)的解.那么题目