zoukankan      html  css  js  c++  java
  • 题解 P5335 [THUSC2016]补退选

    \[\text{题目大意} \]

    \(\quad\)本题就是每次对一个字符执行 \(3\) 种操作:

    • 操作1:插入一个字符串 \(s\)
    • 操作2:弹出一个字符串 \(s\)
    • 操作3:询问以字符串 \(s\) 为前缀的数量最早在哪个事件后 超过 \(x\)

    注意:

    1. 同一时刻可以存在多个完全相同的字符串。
    2. 保证删除的数存在。
    3. 操作的编号就是事件编号,包括操作1,2,3。
    4. 另外操作强制在线,上一次的答案要取绝对值。
    5. 好像要开 long long,否则会WA

    \(\quad\)因为是询问字符串存在的问题,考虑使用字典树求解,用 \(sz_i\) 表示编号为 \(i\) 的点,每次插入字符串路径上的点 \(sz_i+1\) ,删除字符串时字符串路径上的点 \(sz_i-1\) (基本操作)。

    \(\quad\)因为字符串前缀数量一定是逐渐变大,不可能一次从 \(1\) 个加到 \(10\) 个,所以用 vector num_{i,j} 存储字符串编号为 \(i\) 的点第一次超过 \(j\) 数量的最早的事件编号,询问时先判断历史上是否存在,如果 vector 的大小小于 \(x\),就返回。

    本题是真的有点水

    //P5335 [THUSC2016]补退选
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #define int long long
    #define re register int
    #define il inline
    using namespace std;
    il int read()
    {
      int x=0,f=1;char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
      return x*f;
    }
    il void print(int x)
    {
      if(x<0)putchar('-'),x=-x;
      if(x/10)print(x/10);
      putchar(x%10+'0');
    }
    const int N=1e5+5,M=6e6+5;
    int n,ch[M][10],last,sz[M],cnt;
    vector<int>num[M];
    char s[65];
    il void insert(int id)
    {
    	scanf("%s",s+1);
    	int len=strlen(s+1),u=0;
    	for(re i=1;i<=len;i++)
    	{
    		int x=s[i]-'a';
    		if(!ch[u][x])ch[u][x]=++cnt;
    		u=ch[u][x];sz[u]++;
    		if(sz[u]>num[u].size())num[u].push_back(id);//第一次超过
    	}
    }
    il void del()
    {
    	scanf("%s",s+1);
    	int len=strlen(s+1),u=0;
    	for(re i=1;i<=len;i++)
    	{
    		int x=s[i]-'a';
    		u=ch[u][x];sz[u]--;
    	}
    }
    il void query()
    {
    	scanf("%s",s+1);
    	int len=strlen(s+1),u=0;
    	int x=read(),y=read(),z=read();
    	x=(x*last+y)%z;
    	for(re i=1;i<=len;i++)
    	{
    		int x=s[i]-'a';
    		if(!ch[u][x]){last=1;puts("-1");return;}
    		u=ch[u][x];
    	}
    	if((long long)num[u].size()>x)print(last=num[u][x]),putchar('\n');
    	else puts("-1"),last=1;
    }
    signed main()
    {
    	n=read();
    	for(re i=1;i<=n;i++)
    	{
    		int op=read();
    		if(op==1)insert(i);
    		else if(op==2)del();
    		else query();
    	}
    	return 0;
    }
    
  • 相关阅读:
    第五十六课 树中结点的删除操作
    第五十五课 树中节点的清除操作
    常用的机器学习&数据挖掘知识点总结
    leetcode 211. Add and Search Word
    leetcode 349. Intersection of Two Arrays
    leetcode 659. Split Array into Consecutive Subsequences
    leetcode 658. Find K Closest Elements
    leetcode 657. Judge Route Circle
    leetcode 179. Largest Number
    leetcode 660. Remove 9
  • 原文地址:https://www.cnblogs.com/FarkasW/p/15463151.html
Copyright © 2011-2022 走看看