2017 计蒜之道 初赛 第五场 UCloud 的安全秘钥(中等)

Posted 九月旧约

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 计蒜之道 初赛 第五场 UCloud 的安全秘钥(中等)相关的知识,希望对你有一定的参考价值。

每个 UCloud 用户会构造一个由数字序列组成的秘钥,用于对服务器进行各种操作。作为一家安全可信的云计算平台,秘钥的安全性至关重要。因此,UCloud 每年会对用户的秘钥进行安全性评估,具体的评估方法如下:

首先,定义两个由数字序列组成的秘钥 aa 和 bb近似匹配(\approx≈) 的关系。aa 和 bb 近似匹配当且仅当同时满足以下两个条件:

  • |a|=|b|a=b∣,即 aa 串和 bb 串长度相等。
  • 对于每种数字 cc,cc 在 aa 中出现的次数等于cc 在 bb 中出现的次数。

此时,我们就称 aa 和 bb 近似匹配,即 a \approx bab。例如,(1,3,1,1,2)\approx(2,1,3,1,1)(1,3,1,1,2)(2,1,3,1,1)。

UCloud 每年会收集若干不安全秘钥,这些秘钥组成了不安全秘钥集合 TT。对于一个秘钥 ss 和集合 TT 中的秘钥 tt 来说,它们的相似值定义为:ss 的所有连续子串中与 tt 近似匹配的个数。相似值越高,说明秘钥 ss 越不安全。对于不安全秘钥集合 TT 中的每个秘钥 tt,你需要输出它和秘钥 ss 的相似值,用来对用户秘钥的安全性进行分析。

输入格式

第一行包含一个正整数 nn,表示 ss 串的长度。

第二行包含 nn 个正整数 s_1,s_2,...,s_n(1\leq s_i\leq n)s?1??,s?2??,...,s?n??(1s?i??n),表示 ss 串。

接下来一行包含一个正整数 mm,表示询问的个数。

接下来 mm 个部分:

每个部分第一行包含一个正整数 k(1\leq k\leq n)k(1kn),表示每个 tt 串的长度。

每个部分第二行包含 kk 个正整数 t_1,t_2,...,t_k(1\leq t_i\leq n)t?1??,t?2??,...,t?k??(1t?i??n),表示 TT 中的一个串 tt。

输入数据保证 TT 中所有串长度之和不超过 200000200000。

对于简单版本:1\leq n,m\leq 1001n,m100;

对于中等版本:1\leq n\leq 50000,1\leq m\leq 5001n50000,1m500;

对于困难版本:1 \le n \le 50000, 1 \le m \le 1000001n50000,1m100000。

输出格式

输出 mm 行,每行一个整数,即与 TT 中每个串 tt近似匹配的 ss 的子串数量。

样例解释

对于第一个询问,(3,2,1,3)\approx(2,3,1,3)(3,2,1,3)(2,3,1,3),(3,2,1,3)\approx(3,1,3,2)(3,2,1,3)(3,1,3,2);

对于第二个询问,(1,3)\approx(3,1)(1,3)(3,1),(1,3)\approx(1,3)(1,3)(1,3);

对于第三个询问,(3,2)\approx(2,3)(3,2)(2,3),(3,2)\approx(3,2)(3,2)(3,2)。

样例输入

5
2 3 1 3 2
3
4
3 2 1 3
2
1 3
2
3 2

样例输出

2
2
2
#include<cstdio>  
#include<iostream>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
const int maxn=50000+10;  
int a[maxn],b[maxn],n,m,nn;  
int v1[maxn],v2[maxn];  
int main()  
{  
    scanf("%d",&n);  
    for(int i=0; i<n; i++)  
        scanf("%d",a+i);  
    scanf("%d",&nn);  
    while(nn--)  
    {  
        scanf("%d",&m);  
        if(m==1)  
        {  
            scanf("%d",b);  
            int ans=0;  
            for(int i=0; i<n; i++)  
                if(a[i]==b[0]) ans++;  
            printf("%d\n",ans);  
            continue;  
        }  
        memset(v2,0,sizeof(v2));  
        memset(v1,0,sizeof(v1));  
        for(int i=0; i<m; i++)  
        {  
            scanf("%d",b+i);  
            v2[b[i]]++;  
        }  
        int ans=0;  
        int c=0;  
        for(int j=0; j<m; j++)  
            v1[a[j]]++;  
  
        for(int i=1; i<=n; i++)  
            if(v1[i]!=v2[i]) c++;  
        if(c==0) ans++;  
        for(int i=1; i<=n-m; i++)  
        {  
            if(v1[a[i-1]]==v2[a[i-1]]) c++;  
            if(v1[a[i+m-1]]==v2[a[i+m-1]]) c++;  
            v1[a[i-1]]--;  
            v1[a[i+m-1]]++;  
            if(v1[a[i-1]]==v2[a[i-1]]) c--;  
            if(v1[a[i+m-1]]==v2[a[i+m-1]]) c--;  
            if(c==0) ans++;  
        }  
        printf("%d\n",ans);  
    }  
    return 0;  
}  

 

以上是关于2017 计蒜之道 初赛 第五场 UCloud 的安全秘钥(中等)的主要内容,如果未能解决你的问题,请参考以下文章

2017 计蒜之道 初赛 第五场 B. UCloud 的安全秘钥(简单)

2017 计蒜之道 初赛 第五场 C. UCloud 的安全秘钥(中等)

2017 计蒜之道 初赛 第五场 D. UCloud 的安全秘钥(困难)

2018 计蒜之道 初赛 第五场

计蒜之道第五场C题

UCloud 的安全秘钥 (计蒜客初赛第五场)(待解决)