2017 计蒜之道 初赛 第五场@

 A. UCloud 机房的网络搭建

UCloud 刚刚建立一个新机房,近日正在进行网络搭建。机房内有 nn 台服务器和 mm 个分线器,整个机房只有一个网线出口。分线器的作用是将一根网线转换成多根网线。蒜头君也知道每个分线器输出的最大网线根数(不一定要将分线器输出的每根线都用上),问你至少需要使用多少个分线器才能使得每台服务器都有网线可用。

输入格式

第一行输入 n,m(0 \le n,m \le 100)n,m(0n,m100)

第二行输入包含 mm 个整数的数组 A(0 \le A_i \le 10)A(0Ai10) 表示每个分线器输出的最大网线根数。

输出格式

输出最少需要的分线器数量。若不能使得所有服务器都有网线可用,输出一行Impossible

样例说明

一共需要 33 个分线器,最大输出根数分别为 7,3,27,3,2,连接方法如下图所示:

2017 计蒜之道 初赛 第五场@_第1张图片

样例输入

10 4
2 7 2 3

样例输出

3
需要特判一下只有一个或0个服务器的情况

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int N = 100000+7;
int cmp(int x,int y)
{
    return x>y;
}
int a[N];

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i=1;i<=m;i++) scanf("%d", &a[i]);
    sort(a+1,a+m+1,cmp);
    if(n==1||n==0)
    {
        cout<<0<=n)
        {
            cnt=i;
            break;
        }
        n-=a[i];
        a[i+1]-=1;
    }
    if(cnt==-1) printf("Impossible\n");
    else cout<


 B. UCloud 的安全秘钥(简单)

C. UCloud 的安全秘钥(中等)

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

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

  • |a|=|b|a=b,即 aa 串和 bb 串长度相等。
  • 对于每种数字 cccc 在 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(1sin),表示 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(1tin),表示 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 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int N = 100000+7;
int a[N], b[N], vis1[N], vis2[N];
int judge(int k)
{
    for(int i=1;i<=k;i++)
    {
        if(vis1[b[i]]!=vis2[b[i]]) return 0;
    }
    return 1;
}

int main()
{
    int n, m;
    scanf("%d", &n);
    for(int i=1;i<=n;i++) scanf("%d", &a[i]);
    scanf("%d", &m);
    while(m--)
    {
        int k;
        scanf("%d", &k);
        for(int i=1;i<=k;i++)   scanf("%d", &b[i]);
        memset(vis1,0,sizeof(vis1));
        memset(vis2,0,sizeof(vis2));
        for(int i=1;i<=k;i++)
        {
            vis1[a[i]]++,vis2[b[i]]++;
        }
        int cnt=judge(k);
        for(int i=k+1;i<=n;i++)
        {
            vis1[a[i-k]]--,vis1[a[i]]++;
            cnt+=judge(k);
        }
        cout<

困难版本 哈希离线处理+随机化标记

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef unsigned long long LL;
typedef pair pi;
const int N = 1e5+17;
vectorp;
vectordict[N];
LL op[N],b[N];
int a[N], cnt[N], res[N];


int main()
{
    for(int i=1;i<=N-10;i++) op[i]=(LL)rand()*rand();//使每一个数字都有唯一标识且重复率低
    int n, t, k;
    scanf("%d", &n);
    for(int i=1;i<=n;i++) scanf("%d", &a[i]);
    scanf("%d", &t);
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=t;i++)
    {
        scanf("%d", &k);
        if(!cnt[k]) p.push_back(k),cnt[k]++;//记录出现过的区间长度,避免重复计算
        LL now=0;
        for(int j=1;j<=k;j++)
        {
            int x;
            scanf("%d", &x);
            now+=op[x];
        }
        dict[k].push_back(make_pair(i,now));//离线处理时需要的下标
    }
    for(int i=0;i


你可能感兴趣的:(2017 计蒜之道 初赛 第五场@)