题解:CF1671E Preorder

CF1671E 题解

题面

原题传送门

原题传送门

思路

随便思考下发现是树形 dp,考虑 dpu 是以 u 为子树的答案。

于是就有两种情况。

dpu={dpls×dprs2×dpls×dprs

然后讨论两种转移情况下的前提,要是左右子树的字符串不一样,那就可以交换左右子树,成为第二种情况。

接下来考虑左右子树的字符串是否会一样,由于操作可逆,所以只要两个集合中有一个字符串是相同的,两个集合就是可以互相转换的。

于是考虑把字典序最小的当做代表,在 dp 转移的时候顺带统计。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define ll long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int MN=(1<<18)+5,mod=998244353;
ll n,dp[MN];
char buf[1<<23],*p1=buf,*p2=buf,s[MN];
string str[MN];
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=gc();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}return x*f;}
char getc(){char ch=gc();while(ch!='A'&&ch!='B')ch=gc();return ch;}
void dfs(ll u){
    if(u>=(1<<(n-1))){
        dp[u]=1;str[u]=s[u];
        return;
    }
    dfs(ls);dfs(rs);
    if(str[ls]==str[rs]) dp[u]=dp[ls]*dp[rs]%mod;
    else dp[u]=2*dp[ls]*dp[rs]%mod;
    str[u]=s[u];
    if(str[ls]<str[rs]) str[u]+=str[ls]+str[rs];
    else str[u]+=str[rs]+str[ls];
}
int main(){
    n=read();
    for(int i=1; i<(1<<n); i++) s[i]=getc();
    dfs(1);write(dp[1]);putchar('\n');
    return 0;
}//250216
posted @   naroto2022  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
战斗是残酷的,无法做出多余的考虑!