把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷4965】薇尔莉特的打字机(假装有棵Trie树)

点此看题面

  • 一开始有一个长度为\(n\)的字符串,有\(m\)次操作:
    • 加入一个给定字母。
    • 删除最后一个字母(如果串为空则忽略)。
  • 已知每次操作有可能成功有可能失败,问最后可能得到多少种串。
  • \(n,m\le5\times10^6\)

\(Trie\)

考虑暴力的做法,我们直接建出一棵\(Trie\)树。

如果删去一个字符,就是跳回父节点,发现除初始链外所有节点都是原本就能得到的,因此这一操作就相当于初始链上有一个新的节点可以扩展儿子了。

每次加入一个新的字符,就给所有没这个儿子的节点(初始链上尚未更新到的节点除外)加上这个儿子,并更新答案。

假装有棵\(Trie\)

实际上我们并不需要知道到底有多少\(Trie\)树,只要知道对于每种字符,有多少个节点没这个儿子。

\(f_i\)表示没有第\(i\)个儿子的节点数。

加入一个字符\(x\),会新增\(f_x\)个节点,故除\(f_x\)以外的所有\(f_i\)加上\(f_x\)

删去一个字符,初始链的上一个节点就可以扩展儿子,因此给除了已有儿子以外的\(25\)\(f_i\)\(1\)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 5000000
#define X 19260817
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,m,f[30];char s[N+5],ss[N+5];
int main()
{
	RI i,j,t,ans=1;for(scanf("%d%d%s%s",&n,&m,ss+1,s+1),i=1;i<=26;++i) f[i]=1;for(i=1;i<=m;++i)
	{
		if(s[i]=='u') {if(n) for(--n,++ans,j=1;j<=26;++j) f[j]+=(ss[n+1]&31)!=j;continue;}//初始链上跳
		for(t=f[s[i]&31],Inc(ans,t),j=1;j<=26;++j) (s[i]&31)^j&&Inc(f[j],t);//新增节点数即为没有该儿子的节点数
	}return printf("%d\n",ans),0;
}
posted @ 2020-11-02 14:16  TheLostWeak  阅读(186)  评论(0编辑  收藏  举报