当前位置: 代码迷 >> 综合 >> POJ 1240 Pre-Post-erous! (递归+组合数学)
  详细解决方案

POJ 1240 Pre-Post-erous! (递归+组合数学)

热度:100   发布时间:2023-11-15 12:14:21.0

题目链接:http://poj.org/problem?id=1240

题目大意

给定两个m叉树的先序排列和后序排列,
问能有多少种可能的树使得这个序列合法。

题目分析 

递归+组合数学。
设定状态:(l1,r1,l2,r2),
那么我们不难发现l1下标对应的数在第二个区间中出现的下标为
L3,那么这样状态就可以划分了,明显(l1+1,l1+l3-l2,l2,l2,l3-1)
是一个子树的状态。
假设一个状态有k个这样的子状态,那么我们就可以递归处理了,
就意味着(l1,r1,l2,r2)有k个子树,组合的情况是C(m,k),
再乘上每个子树的答案即可。

#include<iostream>
#include<cstring>
using namespace std;#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
int mod=20100501;
const int maxn=30+10;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定两个m叉树的先序排列和后序排列,
问能有多少种可能的树使得这个序列合法。题目分析:
递归+组合数学。
设定状态:(l1,r1,l2,r2),
那么我们不难发现l1下标对应的数在第二个区间中出现的下标为
L3,那么这样状态就可以划分了,明显(l1+1,l1+l3-l2,l2,l2,l3-1)
是一个子树的状态。
假设一个状态有k个这样的子状态,那么我们就可以递归处理了,
就意味着(l1,r1,l2,r2)有k个子树,组合的情况是C(m,k),
再乘上每个子树的答案即可。
*/
int n;
char s1[maxn],s2[maxn];
ll C[30][30];
ll dfs(int l1,int r1,int l2,int r2){if(l1>r1||l2>r2) return 1;if(l1==r1&&l2==r2) return n;ll ans=1;int cnt=0;for(int x=l2,y=l1;x<=r2;){int tmp=x;while(x<=r2&&s2[x]!=s1[y]) x++;int stp=x-tmp;ans=ans*dfs(y+1,y+stp,tmp,tmp+stp-1);x++,y+=stp+1,cnt++;}ans=ans*C[n][cnt];return ans;
}int main(){C[0][0]=1;rep(i,1,21) rep(j,0,i+1)if(j==0||i==j) C[i][j]=1;else C[i][j]=C[i-1][j-1]+C[i-1][j];while(scanf("%d",&n)){if(n==0) break;scanf("%s%s",s1,s2);int len=strlen(s1);printf("%lld\n",dfs(1,len-1,0,len-2));}return 0;
}

 

  相关解决方案