1 条题解
-
0
自动搬运
来自洛谷,原作者为

☯☯枫☯☯
Why son code is not called daughter code?搬运于
2025-08-24 22:24:48,当前版本为作者最后更新于2021-06-27 15:28:25,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
实话说,别想太多,就能速切本题。算法分析:记忆化搜索
第一眼看到可能会想到状压 dp,但事实上没那么复杂。如果要状压的话,状态数有 种,显然在时空上均无法接受。
考虑记忆化搜索。简单地,用 map 记录状态。由于顺序无关,每一轮搜索可以从上一轮之后开始。为了记忆化简单,我们可以把已经包含字符的状态压缩在 里,然后用 表示到 时,使用状态为 的情况总数。然后搜索即可。
下面说明记忆化搜索比状压 dp 优秀。
状压 dp 虽然常数较小,但所有状态几乎是跑满的。由于仅有 个字符,且一个单词很可能包含多种字符,因此在大多数情况下,很快就能组合成一个测试句且情况很容易重复。在已经成为测试句的情况下,剩余的单词选与不选均不会产生影响。记这时已经使用到第 个单词,那么可以直接返回 作为答案。
在最坏情况下,每一层只能获得一个新字符。由于单词长度较长(不超过 ),因此这种情况很难出现。如果出现,可以加入特判剔除这种状况(然鹅本题中并没有这样恶心的数据)。
需要注意的是,在 map 中进行查找时,最好不要直接将状态作为下标进行查找。因为在 map 的机制里,若找不到目标,将自动建立一个空值。而 map 的效率与其元素个数直接相关。这样做将大幅降低 map 的效率,且空间上也不能承受。
下面给出代码:
#include<bits/stdc++.h> #define reg register #define ll long long #define F(i,a,b) for(reg int i=a;i<=b;++i) using namespace std; inline int read(); const int N=105,M=30,all=(1<<26)-1; int b[N],n; char c[N]; ll ans,pww[M] {1}; map<int,ll>f[M]; ll dfs(int fro,int sta){ if(sta==all)return pww[n-fro]; //直接计算得出 if(f[fro].find(sta)!=f[fro].end())return f[fro][sta]; //用 map.find 不会建立空值 ll ans=0; F(i,fro+1,n)ans+=dfs(i,sta|b[i]); f[fro][sta]=ans;//记忆化 return ans; } int main() { F(i,1,26)pww[i]=pww[i-1]<<1ll; n=read(); F(i,1,n) { scanf("%s",c+1); int len=strlen(c+1); F(j,1,len)b[i]|=(1<<(c[j]-'a'));//状态压缩 } ans=dfs(0,0); printf("%lld",ans); return 0; } inline int read() { reg int x=0; reg char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x; }欢迎讨论交流,请点个赞哦~
- 1
信息
- ID
- 5607
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者