Educational Codeforces Round 127 (Rated for Div. 2)
Educational Codeforces Round 127 (Rated for Div. 2)
E. Preorder
题意:给一颗点权仅为AB的完全二叉树,可以对每个点的两个子树进行交换,求前序遍历共有多少种
做法:其实很好想,设dp[x],表示以x为子树的方案有多少种,那么假如两棵子树完全一样,\(dp[x]=dp[l]*dp[r]\),但是两棵子树不一样,那么交换后还会产生\(dp[l]*dp[r]\),即\(dp[x]=2*dp[l]*dp[r]\),所以只需要判断两棵子树是否本质相同就可以了,判断方法可以暴力,因为所有子树的大小和是nlogn的,也可以采用树hash,但是要注意题目后来补充The operation swaps the whole subtrees of two children of the vertex, not just the characters on these children.,所以交换是只能交换两个子树,并不是两个子节点,
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1<<19;
const ll mod=998244353;
ll dp[maxn];
int a[maxn];
char s[maxn];
int N;
string dfs(int x){
if(x*2>N){
dp[x]=1;
string p="";
return p+s[x];
}
int l=x*2;
int r=x*2+1;
//if(s[l]>s[r]) swap(s[l],s[r]);
string p1=dfs(l);
string p2=dfs(r);
if(p1==p2) dp[x]=dp[l]*dp[r]%mod;
else dp[x]=dp[l]*dp[r]*2ll%mod;
if(p1>p2) swap(p1,p2);
return s[x]+p1+p2;
}
int main(){
int n;
cin>>n;
N=(1<<n)-1;
scanf("%s",s+1);
dfs(1);
printf("%lld\n",dp[1]%mod);
return 0;
}