UCloud 的安全秘钥

UCloud 的安全秘钥(困难)

    •  1200ms
    •  262144K

每个 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)s1​​,s2​​,...,sn​​(1si​​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)t1​​,t2​​,...,tk​​(1ti​​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
分析:看了题解发现原来可以集合hash,hash新姿势get,收获巨大,233
   同时不同的len值不超过sqrt(n)个,离线分组对每个len处理即可;

代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#include<unordered_map>
#define rep(i,m,n) for(i=m;i<=n;i++)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
const int maxn=1e5+10;
const int N=5e2+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%mod;p=p*p%mod;q>>=1;}return f;}
int n,m,k,t,a[maxn],cnt[maxn],ret[maxn],tot;
unsigned ll op[maxn],ha[maxn];
vector<pair<int,unsigned ll> >qu[maxn];
vi tmp;
int main()
{
    int i,j;
    rep(i,1,maxn-10)op[i]=(unsigned ll)rand()*rand();
    scanf("%d",&n);
    rep(i,1,n)scanf("%d",&a[i]);
    scanf("%d",&t);
    rep(i,1,t)
    {
        scanf("%d",&m);
        if(++cnt[m]==1&&m<=n)tmp.pb(m);
        unsigned ll now=0;
        rep(j,1,m)scanf("%d",&k),now+=op[k];
        if(m<=n)qu[m].pb(mp(i,now));
    }
    for(i=0;i<tmp.size();i++)
    {
        int now=tmp[i];
        tot=0;
        ha[0]=0;
        rep(j,1,now)ha[tot]+=op[a[j]];
        for(j=now+1;j<=n;j++)
        {
            ++tot;
            ha[tot]=ha[tot-1]+op[a[j]]-op[a[j-now]];
        }
        sort(ha,ha+tot+1);
        for(j=0;j<qu[now].size();j++)
        {
            ret[qu[now][j].fi]=upper_bound(ha,ha+tot+1,qu[now][j].se)-lower_bound(ha,ha+tot+1,qu[now][j].se);
        }
    }
    rep(i,1,t)printf("%d\n",ret[i]);
    return 0;
}
posted @ 2017-06-03 22:58  mxzf0213  阅读(400)  评论(0编辑  收藏  举报