题解: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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!