联想标语

链接 : C-联想标语_2023年第三届 “联想杯”全国高校程序设计在线邀请赛暨第五届上海理工大学程序设计竞赛(同步赛) (nowcoder.com)

题意 : n个操作, 每次给你一个u,和 t 串,u==1 时,如果给定的字符串中有“Lenovo”答案加一, u==2时要删掉以这个串为前缀的前缀,输出有多少个串还包含“Lenovo”(不是真的删掉)

前缀字符串可以想到tire和字符串哈希,笔者只放个tire

 

#include<bits/stdc++.h>

using namespace std;
using ull = unsigned long long;
using ll = long long;
using PII = pair<int,int>;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define endl "\n"
#define pb push_back
const int N=1e6+10;
const int INF=0x3f3f3f3f;
const int mod=998244353;
struct node
{
    int son[26];
    int siz;
}s[N];
int tot;
int res;
int main()
{
    IOS;
    int n; cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        int op; string t; cin >> op >> t;
        int len = t.size();
        if(op == 1)
        {
            int pos = -1;
            for(int k = len - 6; k >= 0 && pos == -1; k --)//至少存在一个,即保证最后一个联想字符串不会被删除,就倒着找pos
                if(t.substr(k, 6) == "lenovo")
                    pos = k, res ++;
            //pos = t.rfind("lenovo");//可以直接用rfind函数
            //if(pos != -1) res ++;
            int now = 0;
            for(int k = 0; k < len; k ++)//构建字典树
            {
                int c = t[k] -'a';
                if(!s[now].son[c])
                    s[now].son[c] = ++ tot;
                now = s[now].son[c];
                if(k >= pos && pos != -1)//前缀字符贡献
                    s[now].siz ++;
            }
            //cout << pos << endl;
        }
        else if(op == 2)
        {
            int num = 0, now = 0;
            for(int k = 0; k < len; k ++)//查找字典树
            {
                int c = t[k] - 'a';
                if(!s[now].son[c]) break;//有没有出现过的字符直接无效
                now = s[now].son[c];
                if(k + 1 == len) num += s[now].siz;//如果包含在前缀里,最后一定是联想字符串的某个字符,否则就不是前缀,只算尾部的贡献,防止重复
            }
            //cout << num << endl;
            cout << res - num << endl;
        }
    }
    return 0;
}

 

posted @ 2023-12-02 13:05  zouyua  阅读(33)  评论(0)    收藏  举报