UVA1362 Exploring Pyramids

Link\text{Link}

题意

给定一棵树的 dfs\text{dfs}ss,求这棵树的形态数量,答案对 10910^9 取模。

有多组数据

分析

我们知道,一棵树的 dfs\text{dfs} 序长这样:

根|子树 1|根|子树 2|根|子树 3|根|……|根|子树 n|根

因为可能会有相同的颜色,所以与根颜色相同的节点也可能为子树。

一棵树的形态个数显然由它子树的形态个数得到,于是我们设 dpi,jdp_{i,j} 为以区间 [i,j][i,j] 为树的形态的个数。

显然,若 i=ji=jdpi,j1dp_{i,j}\Leftarrow1;若 sisjs_i\ne s_jdpi,j0dp_{i,j}\Leftarrow0

接下来考虑 si=sjs_i=s_j 的情况:

  • 只有一颗子树。

此时树的形态为 根|子树 1|根,这时树的形态数量就是子树 11 的形态数量个数,即 dpi,jdpi+1,j1dp_{i,j}\Leftarrow dp_{i+1,j-1}

  • 有多棵子树。

此时树的形态为 根|子树 1|根|其他子树|根,我们发现其中 子树 1根|其他子树|根 是两个子问题,于是我们枚举子树 11 的根端点 k1k-1,满足 si=sks_i=s_k,根据乘法原理及加法原理,dpi,ji+2kj2si=skdpi+1,k1×dpk,jdp_{i,j}\Leftarrow\sum\limits_{i+2\le k\le j-2\land s_i=s_k}dp_{i+1,k-1}\times dp_{k,j}

答案为 dp1,ndp_{1,n}

像这样,一个大区间的答案从小区间得到,我们就想到了区间 dp

然后就是板子了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
    long long x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=310;
const ll mod=1e9;
string s;
int n;
ll dp[N][N];
int main(){
	while(cin>>s){
		n=s.size();
		s=" "+s;//字符串下标从0开始,前面加一个空格使下标从1开始
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)
			dp[i][i]=1;
		for(int l=2;l<=n;l++){
			for(int i=1,j;i+l-1<=n;i++){
				j=i+l-1;
				if(s[i]!=s[j])
					continue;
				dp[i][j]=dp[i+1][j-1];
				for(int k=i+2;k<=j-2;k++)
					if(s[i]==s[k])
						dp[i][j]=(dp[i][j]+dp[i+1][k-1]*dp[k][j]%mod)%mod;
			}
		}
		write(dp[1][n]);
		putchar('\n');
	}
    return 0;
}

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526592

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(2)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起