zoukankan      html  css  js  c++  java
  • 【洛谷4965】薇尔莉特的打字机(假装有棵Trie树)

    点此看题面

    • 一开始有一个长度为(n)的字符串,有(m)次操作:
      • 加入一个给定字母。
      • 删除最后一个字母(如果串为空则忽略)。
    • 已知每次操作有可能成功有可能失败,问最后可能得到多少种串。
    • (n,mle5 imes10^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
    ",ans),0;
    }
    
  • 相关阅读:
    WHYZOJ-#53 线段树区间修改(线段树)
    洛谷-3373 【模板】线段树 2 (线段树)
    暑假训练-藏妹子之处(递推)
    POJ-1258 Agri-Net(kruskal最小生成树)
    POJ-2559 Largest Rectangle in a Histogram(单调栈)
    BZOJ3439 Kpm的MC密码
    BZOJ3438 小M的作物
    BZOJ3436 小K的农场
    BZOJ3437 小P的牧场
    BZOJ1430 小猴打架
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4965.html
Copyright © 2011-2022 走看看