

Input will consist of multiple problem instances. Each instance will consist of a line of the form m s1 s2, indicating that the trees are m-ary trees, s1 is the pre-order traversal and s2 is the post-order traversal.All traversal strings will consist of lowercase alphabetic characters. For all input instances, 1 <= m <= 20 and the length of s1 and s2 will be between 1 and 26 inclusive. If the length of s1 is k (which is the same as the length of s2, of course), the first k letters of the alphabet will be used in the strings. An input line of 0 will terminate the input.
For each problem instance, you should output one line containing the number of possible trees which would result in the pre-order and post-order traversals for the instance. All output values will be within the range of a 32-bit signed integer. For each problem instance, you are guaranteed that there is at least one tree with the given pre-order and post-order traversals.
2 abc cba 2 abc bca 10 abc bca 13 abejkcfghid jkebfghicda
4 1 45 207352860
import java.util.*;
public class Main{
private static long num=1;
private static long numArr[];
private static void initArr(){
numArr=new long[21];
numArr[0]=1;
for(int i=1;i<21;i++){
numArr[i]=numArr[i-1]*i;
}
}
private static long CaculateCom(int subNum,int n){
return numArr[n]/(numArr[n-subNum]*numArr[subNum]);
}
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
initArr();
while(scanner.hasNext()){
int n=scanner.nextInt();
String preOrder=scanner.next();
String postOrder=scanner.next();
num=1;
CaculateTree(n,preOrder,postOrder);
System.out.println(num);
}
}
private static void CaculateTree(int n,String preOrder,String postOrder){
int len=preOrder.length();
if(len==1){
return;
}
int count=0;
preOrder=preOrder.substring(1);
postOrder=postOrder.substring(0,len-1);
while(!"".equals(preOrder)){
int index=postOrder.indexOf(preOrder.charAt(0))+1;
String newPre=preOrder.substring(0,index);
String newPost=postOrder.substring(0,index);
preOrder=preOrder.substring(index);
postOrder=postOrder.substring(index);
count++;
CaculateTree(n,newPre,newPost);
}
num*=CaculateCom(count,n);
}
} #include <string>
#include <tuple>
#include <list>
#include <cstdio>
// 求n的阶乘
long long factorial(int n){
long long r = 1;
for (int i = 1; i <= n; i++){
r *= i;
}
return r;
}
// 求 n, m 的组合 C(n, m)
// 利用 C(n, m) == C(n, n - m) 的特点,计算容易的
long long combination(int n, int m){
int max = m > (n - m) ? m : (n - m);
long long numerator = 1;
for (int i = max + 1; i <= n; i++){
numerator *= i;
}
return numerator / factorial(n - max);
}// 重命名类型,类似于 typedef 作用
using PrePost = std::tuple<std::string, std::string>;
// 给出一棵树的前序+后序,利用最上面注释的原理 // 把每棵子树的前序+后序切分出来
std::list<PrePost> splitSubTrees(std::string const& pre, std::string const& post){
std::list<PrePost> list{};
size_t preIdx = 1;
size_t lastPost = 0;
while (preIdx < pre.size()){
char rootValue = pre[preIdx];
size_t postIdx = post.find(rootValue);
int countOfNode = postIdx - lastPost + 1;
list.emplace_back(std::make_tuple( pre.substr(preIdx, countOfNode), post.substr(lastPost, countOfNode) ) );
preIdx += countOfNode;
lastPost += countOfNode;
}
return list;
}
// 递归的求解每一层的可能性,直到树中只剩一个或者零个结点
long long calculateNumOfPossibilities(int m, std::string const& pre, std::string const& post){
if (pre.size() == 0 || pre.size() == 1){
return 1;
}
std::list<PrePost> subTrees = splitSubTrees(pre, post);
long long result = combination(m, subTrees.size());
for (PrePost const& prePost : subTrees){
result *= calculateNumOfPossibilities(m,std::get<0>(prePost), std::get<1>(prePost));
}
return result;
}
int main(){
int m;
char pre[30];
char post[30];
while (scanf("%d %s %s", &m, pre, post) != EOF){
printf("%lld\n", calculateNumOfPossibilities(m, pre, post));
}
return 0;
} #include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<map>
using namespace std;
int ans, m;
char pre[27], post[27];
map<char, int> postidx;
//相应字母在post中的下标,因为每个节点都是唯一的,所以可以建立一个索引
void Count(int preS, int preE, int postS, int postE);
int mCk(int m, int k);
int main()
{
while (scanf("%d %s %s", &m, pre, post) != EOF)
{
ans = 1;
for (int i = 0; i<strlen(post); i++)
postidx[post[i]] = i;
Count(0, strlen(pre) - 1, 0, strlen(post) - 1);
printf("%d\n", ans);
}//while
return 0;
}//main
void Count(int preS, int preE, int postS, int postE)//指示先序和后序某段区间
{
if (preS >= preE)
return;
int i = preS + 1, cnt = 0;//cnt统计子树的个数,i是标识当前树的根节点的子树的根节点,在pre中的下标
int idx = postidx[pre[i]];
while (i <= preE)
{
Count(i, i + idx - postS, postS, idx);
cnt++;
if (idx != postE - 1)//子树不止一个,把要递归搜索的树的区间整体移动
{
i += idx - postS + 1; //idx-postS是刚刚递归过的子树的大小
//i要跨过这个区间,找到下一个要搜索的根节点
postS = idx + 1; //post的区间起始位置也要前进1位
idx = postidx[pre[i]];//idx重新定位下一个要搜索的子树根节点在post中的下标
}
else
break;//完成对当前区间中所有字数根节点的全部搜索
}
ans *= mCk(m, cnt);//计算排列组合,cnt表示当前层有几个子树
}
int mCk(int m, int k)
{
int numerator = 1, denominator = 1;
for (int i = 0; i<k; i++, m--)
numerator *= m;
for (int i = 1; i <= k; i++)
denominator *= i;
return numerator / denominator;
}
#include<iostream>
#include<string>
using namespace std;
int c[21][21],n;
long long solve(string pre,string post){
long long sum=1;
int num=0,k=0,i;
pre.erase(pre.begin());
post=post.substr(0, post.length()-1);
while (k<pre.length())
for (i=0;i<post.length();i++)
if (pre[k]==post[i]){
sum*=solve(pre.substr(k,i-k+1),post.substr(k,i-k+1));
num++,k=i+1;break;
}
sum*=c[num][n];
return sum;
}
void init(){
int i,j;
c[0][1]=c[1][1]=1;
for(i=2;i<21;i++)
for(c[0][i]=1,j=1;j<=i;j++)
if(i==j) c[j][i]=1;
else c[j][i]=c[j-1][i-1]+c[j][i-1];
}
int main(){
string pre,post;
init();
while(cin>>n>>pre>>post&&n)
cout<<solve(pre,post)<<endl;
}
#include <iostream>
#include <string>
using namespace std;
// pre: root,child1->childm
// post:child1->childm,root
void getPosssible(string pre, string post, int m, int& ans) {
if(pre == "") return;
if (pre.front() == post.back()) {
// 位于同一颗根节点的树上
int len = post.size();
ans *= m;
getPosssible(pre.substr(1,len-1), post.substr(0,len-1), m, ans);
} else {
// 位于不同根节点的树上
int rootNum = 0;
while (!pre.empty()) {
char root1 = pre.front();
int root1Len = post.find(root1) ;
getPosssible(pre.substr(1, root1Len), post.substr(0, root1Len), m, ans);
rootNum++;
int restLen = post.size() - root1Len;
if(!restLen) break;
pre = pre.substr(root1Len+1, restLen);
post = post.substr(root1Len+1, restLen);
}
// 得到分支数
int a = 1, b = 1;
for (int i = 0 ; i < rootNum; i++) {
a *= (m - i);
b *= (rootNum - i);
}
ans *= (a / b);
}
}
int main() {
int m;
while (cin >> m && m != 0) {
string pre, post;
cin >> pre >> post;
int ans = 1;
int len = post.size();
getPosssible(pre.substr(1,len-1), post.substr(0,len-1), m, ans);
cout << ans << '\n';
}
}
// 64 位输出请用 printf("%lld") #include <iostream>
using namespace std;
//这里认为子树位置一样就算同一种,所以是用组合数而不是排列数
//注意组合数的求法:C(n,k)=C(n-1,k)+C(n-1,k-1)
const int M = 25;
int C[M][M];
int m;
string preTr, postTr;
int diffTree(string pre, string post)
{
if(pre.size() == 1 && post.size()==1)
return 1;
int res = 1;
pre.erase(0, 1);
post.pop_back();
int i=0, j=0;
int subtree = 0;
while(i<pre.size())
{
int k = post.find(pre[i], j);
int trees = diffTree(pre.substr(i, k-j+1), post.substr(j, k-j+1));
subtree++;
res*=trees;
i+=(k-j+1);
j=k+1;
}
return res*C[m][subtree];
}
int main()
{
C[0][0]=1;
for(int i=1;i<M;i++)
{
C[i][0]=1;
for(int j=1;j<i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
C[i][i]=1;
}
while(cin>>m>>preTr>>postTr)
cout<<diffTree(preTr, postTr)<<endl;
return 0;
}
// 64 位输出请用 printf("%lld") #include<iostream>
#include<string>
#include<vector>
using namespace std;
/*
输入描述:
输入将包含多个问题实例。每个实例将由一行m s1 s2组成,表示树是m元树,s1是前序遍历,s2是后序遍历。所有遍历字符串将由小写字母字符组成。
对于所有输入实例,1<=m<=20,s1和s2的长度将介于1和26之间(包括1和26)。如果s1的长度是k(当然,这与s2的长度相同),则字母表的前k个字母将用于字符串。
输入行0将终止输入。
*/
/*
输出描述:
对于每个问题实例,您应该输出一行,其中包含可能的树的数量,这将导致实例的预排序和后排序遍历。所有输出值都将在32位有符号整数的范围内。
对于每个问题实例,保证至少有一个树具有给定的预排序和后排序遍历。
*/
//保存子树的前序和后序遍历结果
struct SubTree{
SubTree(const string& pre,const string& post)
:_pre(pre)
,_post(post)
{}
string _pre;
string _post;
};
//求n的阶乘
long long Fac(int n)
{
long long f = 1;
for(int i = 1; i <= n; i++)
{
f *= i;
}
return f;
}
//求C(n,m) = C(n,n-m)
long long CalcCom(int n,int m)
{
m = m < (n-m)?m:(n-m);
long long r = 1;
for(int i = n; i >= n-m+1; i--)
{
r *= i;
}
return r / Fac(m);
}
vector<SubTree> CalcSubTree(const string& pre,const string& post)
{
size_t subRootPreIdx = 1;
size_t postFirst = 0; //子树在后序遍历结果中第一个元素的位置
vector<SubTree> v;
while(subRootPreIdx < pre.size())
{
//确定子树的根结点
char subRoot = pre[subRootPreIdx];
//确定根在后序遍历结果中的位置
char subRootPostIdx = post.find(subRoot);
//计算该子树中结点的个数
size_t subTreeNodeCount = subRootPostIdx - postFirst + 1;
//找到该棵子树钱些许遍历结果 - 找到该棵子树后序遍历结果 - 构造子树
SubTree subTree(pre.substr(subRootPreIdx,subTreeNodeCount),post.substr(postFirst,subTreeNodeCount))
;
v.push_back(subTree);
//根据下一棵子树根在前序遍历结果中的下标
subRootPreIdx += subTreeNodeCount;
//更新下一棵子树中第一个结点在后序遍历中的下标
postFirst += subTreeNodeCount;
}
return v;
}
long long CalcTreePossible(int m,const string& pre,const string& post)
{
//如果树中只有一个结点 -- 树的可能性是唯一的
if(1 == pre.size()){
return 1;
}
//先找出每一层根结点的所有子树
vector<SubTree> v = CalcSubTree(pre,post);
//计算根结点子树的可能性 --- 组合
long long result = CalcCom(m,v.size());
for(auto& e: v){
result *= CalcTreePossible(m,e._pre,e._post); //递归
}
return result;
}
int main()
{
int m; //多少叉树
string pre,post;
while(cin >> m >> pre >> post)
{
if(m == 0){
break;
}
cout << CalcTreePossible(m,pre,post) << endl;
}
return 0;
} #include <iostream>
#include <string>
using namespace std;
long long Factorial(int n){//求一个数的阶乘
if (n == 0){
return 1;
}
long long mul = 1;
while (n){
mul *= n;
n--;
}
return mul;
}
long long sum = 1;//全局变量,用来保存乘积结果
void AllPossible(int n, string& str1, string& str2, int l1, int r1, int l2, int r2){
l1 += 1;
r2 -= 1;
int count = 0;//统计当前树有多少子树
int pre = 0;
while (l1<=r1){
pre = l2;
while (l2<=r2&&str1[l1]!=str2[l2]){
l2++;
}
AllPossible(n,str1,str2,l1,l1+l2-pre,pre,l2);
count++;//每递归一次,子树的个数加1
l1 = l1 + l2 - pre + 1;//计算下一次l1的起始位置
l2++;//下一次l2的起始位置
}
sum *= Factorial(n)/(Factorial(count)*Factorial(n-count));//当前树所有子树的组合
}
int main(){
int n = 11;
string str1;
string str2;
while (cin >> n >> str1 >> str2){
AllPossible(n, str1, str2, 0, str1.size() - 1, 0, str2.size() - 1);
cout << sum << endl;
}
return 0;
} import java.util.*;
class SubTree{
public SubTree(String pre,String post){
this.pre = pre;
this.post = post;
}
String pre;
String post;
}
public class Main{
//计算阶乘
public static long fac(int n){
long f = 1;
for(int i = 1;i <= n;i++){
f *= i;
}
return f;
}
//计算C n m
public static long calcCom(int n,int m){
m = m < (n - m)? m : (n - m);
long r = 1;
for(int i = n;i >= n - m + 1;i--){
r *= i;
}
return r / fac(m);
}
public static List<SubTree> calcSubTree(String prev,String post){
//子树的根在前序遍历结果中的位置
int subRootPreIdx = 1;
//后序遍历
int postFirst = 0;
List<SubTree> subTreeList = new ArrayList<>();
while(subRootPreIdx < prev.length()){
//确认该棵子树的根节点
char rootSub = prev.charAt(subRootPreIdx);
int subRootPostIdx = post.indexOf(rootSub);
int subTreeNodeCount = subRootPostIdx - postFirst + 1;
//从前序和后续遍历结果中分离出该棵子树的前序和后序遍历结果
SubTree subTree = new SubTree(
prev.substring(subRootPreIdx,subRootPreIdx + subTreeNodeCount),
post.substring(postFirst,postFirst + subTreeNodeCount)
);
subTreeList.add(subTree);
//继续分离下一棵子树
subRootPreIdx += subTreeNodeCount;
postFirst += subTreeNodeCount;
}
return subTreeList;
}
public static long CalcTreePossible(int m,String pre,String post){
if(pre.isEmpty() || pre.length() == 1){
return 1;
}
//先分离出根节点有多少棵树
List<SubTree> subTree = calcSubTree(pre,post);
//根节点子树可能性的组合结果
long result = calcCom(m,subTree.size());
//根的子树有多少种可能性
for(SubTree e : subTree){
result *= CalcTreePossible(m,e.pre,e.post);
}
return result;
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int m = in.nextInt();
if(m == 0){
break;
}
//接收子树的前序和后续遍历结果
String pre = in.next();
String post = in.next();
System.out.println(CalcTreePossible(m,pre,post));
}
}
} #include"iostream"
using namespace std;
/*计算组合数c(m, n)*/
int f(int k, int m, int n){
if(k== n+ 1|| m== 0|| m> (n- k+ 1)){
if(m== 0){return 1;}
else{return 0;}
}else{
return f(k+ 1, m, n)+ f(k+ 1, m-1, n);
}
}
/*以该先序和后序能形成的n叉树的个数*/
int g(string nlr, string lrn, int n){
if(nlr.length()== 1){return 1;}// 结束条件
else{
int fe= 0, sum= 1, m= 0;
while(fe< nlr.length()-1){// 考虑固定一种子树的顺序 则n叉树的个数等于各个子树所能形成n叉树个数的连乘积
int len= lrn.find(nlr[fe+ 1])+ 1;
string s1= nlr.substr(fe+ 1, len);
string s2= lrn.substr(0, len);
sum*= g(s1, s2, n);m++;fe+= len;
lrn= lrn.substr(len);
}
return f(1, m, n)* sum;// 考虑全部的顺序
}
}
int main(){
string s1, s2;int n;
while(cin>> n>> s1>> s2){
cout<< g(s1, s2, n)<< endl;
}
} #include <iostream>
#include <string>
const int N = 1000;
int n;
using namespace std;
int c[N][N]; //c[i][j] 表示从i个数里面选j个
int solve(string pre,string post)
{
if(pre.size() == 1 && pre[0] == post[0]) return 1;
pre.erase(pre.begin());
post.erase(post.end() - 1);
int sum = 1;
int k = 0;
int cnt = 0 ;//记录本层中有几棵树
for(int i = 0; i < post.size(); i ++ )
{
if(post[i] == pre[k])
{
sum *= solve(pre.substr(k,i - k + 1),
post.substr(k,i - k + 1));
k = i + 1;
cnt ++;
}
}
sum *= c[n][cnt];
return sum;
}
int main()
{
c[0][0] = 1;
for(int i = 1; i < N; i ++)
for(int j = 0; j <= i; j ++)
{
c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
}
string pre,post;
while(cin >> n >> pre >> post)
{
cout << solve(pre,post) << endl;
}
return 0;
}
#include<iostream>
#include<string>
using namespace std;
long long N[21],num;
int n;
void ComputeN()
{
N[0] = 1;
for(int i = 1;i < 21;i++)
{
N[i] = N[i - 1] * i;
}
}
int CMN(int m,int n)
{
return N[n] / (N[m] * N[n - m]);
}
void DFS(string pre,string post)
{
if(pre.size() == 1) return;
int count = 0;
pre = pre.substr(1);
post = post.substr(0,post.size() - 1);
while(pre != "")
{
int index = post.find(pre[0]) + 1;
string newpre = pre.substr(0,index);
string newpost = post.substr(0,index);
pre = pre.substr(index);
post = post.substr(index);
count++;
DFS(newpre,newpost);
}
num *= CMN(count,n);
}
int main()
{
string s1,s2;
ComputeN();
while(cin >> n >> s1 >> s2)
{
num = 1;
DFS(s1,s2);
cout << num << endl;
}
return 0;
} #include <iostream>
#include <string>
int n;
long long fn;
long long total;
void CountChildren(const std::string& Pre, int s1, int e1,
const std::string& Post, int s2, int e2){
int i = s1;
int cnt = 0;
int back_s2 = s2;
while(i < e1){
for (int j = e2-1; j >= s2; j--){
if (Pre[i] == Post[j]){
cnt++;
int childLen = j - s2;
if (childLen == 0){
i++;
s2++;
break;
}else{
if (i + 1 < Pre.size()){
CountChildren(Pre, i+1, i + 1 + childLen, Post, s2, j);
}
i = i + 1 + childLen;
s2 = s2 + 1 + childLen;
}
}
}
}
long long poss = 1;
for (int i = 1; i <= cnt; i ++){
poss = poss * i;
}
long long poss2 = 1;
for (int i = 1; i <= n-cnt; i++){
poss2 = poss2 * i;
}
total = total * (fn / poss / poss2);
}
int main(){
std::string N, Pre, Post;
while(std::cin >> N){
std::cin >> Pre >> Post;
n = std::stoi(N);
fn = 1;
total = 1;
for (int i = 1; i <= n ; i++){
fn = fn * i;
}
CountChildren(Pre, 1, Pre.size(), Post, 0, Post.size()-1);
std::cout << total << std::endl;
}
return 0;
} //m叉树根节点孩子结点个数为n,可以得到组合数C(m,n),递归调用根节点的各个孩子节点为根
//的子树,得到n个组合数.这n个组合数与组合数C(m,n)的和即为以先序与后序序***定的树的
//总个数
//其中每个阶段计算组合数采用分而治之的思想,类比二叉树先序后序递归调用得中序的方式
//可以将先序和后序分为n个子树对应的先序后序子序列,统计子序列的个数即为可得到n,
#include<cstdio>
(802)#include<cstring>
#include<map>
using namespace std;
char pre[30],post[30];
int m;
map<char,int> mp;
int ccal(int n1,int m1){
int sum=1;
for(int i=1;i<=m1;++i){
sum=sum*(n1-m1+i)/i;
}
return sum;
}
int cal(int pl,int pr,int pol,int ***bsp; if(pl>=pr){
return 1;
}
int ans=1,i=pl+1,l=pol,r=mp[pre[pl+1]];
int sum=0;
while(i<=pr){
ans*=cal(i,i+r-l,l,r);
sum++;
i=i+r-l+1;
l=r+1;
if(i<=pr)
r=mp[pre[i]];
}
ans*=ccal(m,sum);
return ans;
}
int main(){
while(scanf("%d %s %s",&m,pre,post)!=EOF){
int len=strlen(pre);
mp.clear();
for(int i=0;i<strlen(post);++i){
mp[post[i]]=i;
}
int cnt=cal(0,len-1,0,len-1);
printf("%d\n",cnt);
}
return 0;
} #include <bits/stdc++.h>
using namespace std;
int com(int n,int m)
{
int up=1,down=1;
for(int i=1;i<=n;up*=(m-i+1),down*=i++);
return up/down;
}
int dfs(string pre,string post,int m)
{
if(pre.length()==1)return 1;
vector<string> preSplit,postSplit;
int preCut=1,postCut1=0,postCut2;
while(preCut!=pre.length())
{
postCut2=post.find(pre[preCut]);
preSplit.push_back(pre.substr(preCut,postCut2-postCut1+1));
postSplit.push_back(post.substr(postCut1,postCut2-postCut1+1));
preCut+=postCut2-postCut1+1;
postCut1=postCut2+1;
}
int n=preSplit.size(),sum=1;
for(int i=0;i<n;++i)sum*=dfs(preSplit[i],postSplit[i],m);
return sum*com(n,m);
}
int main()
{
int m;
string pre,post;
cin>>m>>pre>>post;
cout<<dfs(pre,post,m);
return 0;
}
#include<iostream>
(720)#include<vector>
#include<string>
using namespace std;
const int N = 21;
long long sum = 1;
long long arr[N];
void Initial()
{
arr[0] = 1;
for (int i = 1; i < N; i++)
arr[i] = arr[i - 1] * i;
}
long long Cnm(int n,int m)
{
return arr[n] / (arr[m] * arr[n - m]);
}
void PrePost(int m ,string a ,string b)
{
if (a.size() > 1)
{
if (a[1] == b[b.size() - 2])
{
sum *= Cnm(m, 1);
a.erase(0, 1);
b.erase(b.size() - 1);
PrePost(m, a, b);
}
else
{
int k = 0;
vector<string> x,y;
int i;
while (a.size() > 1)
{
for (i = 0; i < b.size(); i++)
{
if (b[i] == a[1])
{
k++;
break;
}
}
x.push_back(a.substr(1, i + 1));
y.push_back(b.substr(0, i + 1));
a.erase(1, i + 1);
b.erase(0, i + 1);
}
sum *= Cnm(m, k);
for (int i = 0; i < x.size(); i++)
{
PrePost(m, x[i], y[i]);
}
}
}
}
int main()
{
Initial();
int n;
string a, b;
while (cin>>n)
{
sum = 1;
cin >> a >> b;
PrePost(n, a, b);
cout << sum << endl;
}
}