zoukankan      html  css  js  c++  java
  • (计蒜客)UCloud 的安全秘钥

    UCloud 的安全秘钥

    题意

    给出一个数组 s 串,和数组 t 串,那么如果两者长度相同且两者所含的数字全部相同,则说这两个串相似。
    给定原始串 S ,以及 m 个询问 T 串,问 S 串有多少个连续子串和 T 串相似。

    分析

    2017年计蒜之道第五场的题目。题目很有趣,虽然比赛里只水出了中等难度。看了题解,学到了新姿势!

    这道题,为了优化复杂度,就是要快速判断两个数组是否完全相同,

    对于中等难度,询问的次数很少,那么我们就要加快 T 和 S 的子串的比较速度,那么可以把 1到50000 (n <= 50000)分别映射到64位无符号整型数(允许自然溢出),对于查询的串,把对应的映射后的值加起来,和 S 的子串(也是映射后的)分别比较即可。复杂度 (O(nm))

    对于困难难度,询问次数1e5,但是注意到题目给出的查询的串 T 的总长度 (len) <= 2e5 ,那么最多只有 (sqrt{len}) 种长度,对于每一种长度,求出 S 的所有子串,并把这些子串和查询的串全部放到一个数组里面排序,通过遍历一遍数组即可算出答案。复杂度(O(nlognsqrt{len}))

    我把困难难度的代码再交到中等难度题目里面,发现运行时间893ms,而 (O(nm)) 的算法只需要66ms,因为困难难度的代码的复杂度已经和查询的次数无关了,对于不同数据,设计不同的算法,要充分利用题目给出的信息。

    code ((O(nm))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 5e4 + 10;
    int n, m;
    int a[MAXN];
    int t[MAXN];
    unsigned long long Z[MAXN];
    int main() {
        srand(timezone);
        for(int i = 0; i < MAXN; i++) {
            Z[i] = (unsigned long long)rand() * rand() * rand() * rand();
        }
        cin >> n;
        for(int i = 0; i < n; i++) {
            cin >> a[i];
        }
        cin >> m;
        while(m--) {
            int k, num = 0;
            cin >> k;
            if(k > n) {
                puts("0");
                continue;
            }
            int cnt = 0;
            unsigned long long A = 1, T = 1;
            for(int i = 0; i < k; i++) {
                cin >> t[i];
                T += Z[t[i]];
                A += Z[a[i]];
            }
            if(A == T) {
                cnt++;
            }
            for(int i = k; i < n; i++) {
                A -= Z[a[i - k]];
                A += Z[a[i]];
                if(A == T) cnt++;
            }
            cout << cnt << endl;
        }
        return 0;
    }
    

    code ((O(nlognsqrt{len}))

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    const int MAXN = 1e5 + 10;
    int n, m;
    int s[MAXN];
    ull Z[MAXN];
    struct A {
        int id, k;
        ull num;
        bool operator<(const A&other) {
            return k < other.k;
        }
    } a[MAXN];
    struct node {
        int q, id;
        ull num;
        node() {}
        node(int q_, int id_, ull num_): q(q_), id(id_), num(num_) {}
        bool operator<(const node&other) {
            if(num != other.num) return num < other.num;
            return q > other.q;
        }
    } d[MAXN * 2];
    int ans[MAXN * 2];
    int main() {
        srand(timezone);
        for(int i = 0; i < MAXN; i++) {
            Z[i] = (ull)rand() * rand() * rand() * rand();
        }
        cin >> n;
        for(int i = 0; i < n; i++) {
            cin >> s[i];
        }
        cin >> m;
        for(int i = 0; i < m; i++) {
            cin >> a[i].k;
            a[i].id = i;
            for(int j = 0; j < a[i].k; j++) {
                int p;
                cin >> p;
                a[i].num += Z[p];
            }
        }
        sort(a, a + m);
        int l = 0, r = 0;
        while(r < m) {
            int cnt = 0;
            d[cnt++] = node(1, a[r].id, a[r].num);
            while(r < m && a[r + 1].k == a[r].k) {
                r++;
                d[cnt++] = node(1, a[r].id, a[r].num);
            }
            int k = a[r].k;
            if(k > n) {
                ans[a[l].id] = 0;
                continue;
            }
            ull sum = 0;
            for(int i = 0; i < k; i++) {
                sum += Z[s[i]];
            }
            if(k) d[cnt++] = node(0, 0, sum);
            for(int i = k; i < n; i++) {
                sum -= Z[s[i - k]];
                sum += Z[s[i]];
                d[cnt++] = node(0, 0, sum);
            }
            sort(d, d + cnt);
            int l1 = 0, r1 = 0, l2 = 0, r2 = 0;
            while(l1 < cnt) {
                int flg = 0;
                for(int i = l1; i < cnt; i++) {
                    if(d[i].q) {
                        l1 = i;
                        flg = 1;
                        break;
                    }
                }
                if(!flg) break;
                r1 = l1;
                while(r1 < cnt && d[r1 + 1].q && d[r1 + 1].num == d[r1].num) r1++;
                int l2 = r1 + 1, r2 = l2;
                if(l2 < cnt && !d[l2].q && d[l2].num == d[r1].num) {
                    while(r2 < cnt && !d[r2 + 1].q && d[r2 + 1].num == d[r2].num) r2++;
                    for(int i = l1; i <= r1; i++) {
                        ans[d[i].id] = r2 - l2 + 1;
                    }
                    l1 = r2 + 1;
                } else l1 = r2;
            }
            r++;
        }
        for(int i = 0; i < m; i++) {
            cout << ans[i] << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    db2 v11 安装测试
    DB2支持的三种表空间SMS、DMS、DMS的自动存储
    linux几种快速清空文件内容的方法
    修改文件或者文件夹权限
    db2start启动失败
    db2icrt创建实例,提示主机名无效
    浏览器内核以及在各个浏览器的前缀
    程序的三大结构(顺序结构、选择结构、循环结构)
    数组中元素的排序(常用的冒泡排序、选择排序、快速排序)
    数组的api以及api的简单使用
  • 原文地址:https://www.cnblogs.com/ftae/p/6945365.html
Copyright © 2011-2022 走看看