• [考试总结]ZROI-21-CSP7连-EXTRA1 总结


    #T1 Str

    #题意简述

    定义两个字符串相似为各个字符数相等;给定一个长度为 (n(nleq10^5)) 的字符串 (s),求一个尽可能短的前缀 (t) 满足可以将 (s) 分为大于等于 (2) 段,要求每段长度相同,除第一段与 (t) 相等外,其余段与 (t) 相似。

    #大体思路

    (n) 的因数最多只有 (O(sqrt n)) 个,可以暴力枚举 (n) 的小于等于 (dfrac n 2) 的因数,直接进行判断,一个极为宽松的时间复杂度为 (O(nsqrt n)),或者也可以看作循环 (n) 次,每个循环里 (O(dfrac{1}k)),整体为 (O(nlog n)).

    #Code

    const int N = 100010;
    const int INF = 0x3fffffff;
    
    char s[N]; int n, cnt[N][26], standard[26];
    
    inline bool check(int l, int r) {
        for (int i = 0; i < 26; ++ i)
          if (cnt[r][i] - cnt[l - 1][i] != standard[i])
            return false;
        return true;
    }
    
    int main() {
        scanf("%s", s); n = strlen(s);
        for (int i = 0; i < n; ++ i)
          ++ cnt[i + 1][s[i] - 'a'];
        for (int i = 1; i <= n; ++ i)
          for (int j = 0; j < 26; ++ j)
            cnt[i][j] += cnt[i - 1][j];
        for (int l = 1; l <= n >> 1; ++ l) if (!(n % l)) {
            int is_answer = true;
            for (int i = 0; i < 26; ++ i)
              standard[i] = cnt[l][i];
            for (int i = l + 1; i <= n; i += l)
              if (!check(i, i + l - 1)) {
                  is_answer = false; break;
              }
            if (is_answer) {
                for (int i = 0; i < l; ++ i)
                  putchar(s[i]);
                return 0;
            }
        }
        puts("-1"); return 0;
    }
    

    #T2 Subset

    #题意简述

    给出一个长度为 (n(1leq nleq10^5)) 的序列 (A) ,求 (A) 的所有长度为 (k(1leq kleq50)) 的子序列的最大值之和 (mod 10^9+7)

    #大体思路

    我们来直接考虑元素 (x) 造成的贡献,显然只有当子序列中的数 (b_i(1leq ileq k)) 都小于等于 (x) 时才会造成 (x) 的贡献,于是不难想到将序列自小到大排序,于是 (a_i(1leq ileq n)) 的贡献为 (dbinom{i-1}{k-1}cdot a_i)。时间复杂度为 (O(nk)),瓶颈为预处理组合数,当然也可以采用线性求阶乘、逆元的方式优化到 (O(nlog n)),此时时间复杂度瓶颈为快速排序。

    #Code

    #define ll long long
    
    const int N = 100010;
    const ll MOD = 1e9 + 7;
    const int INF = 0x3fffffff;
    
    template <typename T> inline void read(T &x) {
        x = 0; int f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }
    
    int n, k; ll C[N][55], a[N], ans;
    
    inline void init_C(int x, int y) {
        for (int i = 0; i <= x; ++ i) C[i][0] = 1;
        for (int i = 1; i <= x; ++ i)
          for (int j = 1; j <= i && j <= y; ++ j) {
              if (j == i) {C[i][j] = 1; break;}
              C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
          }
    }
    
    int main() {
        read(n); read(k); init_C(n, k);
        for (int i = 1; i <= n; ++ i) read(a[i]);
        sort(a + 1, a + n + 1);
        for (int i = k; i <= n; ++ i)
          (ans += C[i - 1][k - 1] * a[i] % MOD) %= MOD;
        printf("%lld", ans); return 0;
    }
    

    #T3 Pair

    #题意简述

    给出一个整数 (n(nleq20)) ,求满足 (forall(a,b)in S,1leq a<bleq n)(gcd(a,b)=1) ,并且不存在一个划分的集合 (S) 的数量 (mod 10^9).

    定义一个集合 (S) 存在划分为 (exists xin[2,n])(forall(a,b)in S) 要么满足 (a<x ext{ and }b<x),要么满足 (ageq x ext{ and }bgeq x).

    #大体思路

    首先不难发现这样的数对最多有 (n^2) 个,于是显然可以预处理得到。

    发现一个集合不存在划分,即意味着对于集合 (S={(a_1,b_1),(a_2,b_2),dots,(a_k,b_k)}),应当有

    [igcuplimits_{i=1}^k[a_i,b_i]=[1,n], ]

    考虑设计 DP 解决计数问题。假设我们已经得到了所有 (m) 个可行的数对(按先 (a)(b) 的顺序从小到大排序),设 (f_{i,j}) 表示考虑了前 (i) 个二元组,并集为 ([1,j]) 的方案数,最终答案为 (f_{m,n}).

    来考虑如何转移,如果不选新加入的二元组,那么方案数为 (f_{i-1,j}),即具有转移 (f_{i-1,j} o f_{i,j}),如果新加入的二元组 ((a,b)) 满足 (aleq j),意味着将其并入得到的集合不会存在划分,新得到的并集应当为 ([1,max{j,b}]),于是具有转移 (f_{i-1,j} o f_{i,max{j,b}})。一个极为宽松的时间复杂度上界为 (O(n^3)).

    #Code

    #define ll long long
    
    const ll MOD = 1e9;
    const int N = 2000010;
    const int INF = 0x3fffffff;
    
    template <typename T> inline void read(T &x) {
        x = 0; int f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }
    
    int n, npr[N][2], cnt; ll f[N][21];
    
    ll gcd(ll x, ll y) {return y ? gcd(y, x % y) : x;}
    
    int main() {
        read(n);
        for (int i = 1; i < n; ++ i)
          for (int j = i + 1; j <= n; ++ j)
            if (gcd(i, j) == 1) npr[++ cnt][0] = i, npr[cnt][1] = j;
        f[0][1] = 1;
        for (int i = 1; i <= cnt; ++ i)
          for (int j = 1; j <= n; ++ j) {
              f[i][j] = (f[i][j] + f[i - 1][j]) % MOD;
              if (npr[i][0] <= j)
                (f[i][max(npr[i][1], j)] += f[i - 1][j]) %= MOD;
          }
        printf("%lld", f[cnt][n]);
        return 0;
    }
    

    #T4 Match

    #题意简述

    给定 (n(nleq10^5)) 个字符串 (S_i),有 (m(mleq10^5)) 个询问,每次给出一个前缀 (T_1) 和一个后缀 (T_2),问有多少个串 (S_i) 满足 (S_i=T_1RT_2(|R|geq0))

    数据范围满足 (sum|S_i|+sum|T|leq10^6).

    #大体思路

    先考虑将所有字符串插入一棵 trie 中,先考虑前缀要求 (T_1),假设得到 (T_1) 的结束点为 (x), 这限制了所有答案的 (T_2) 的起始点一定在 (x) 的子树中,于是我们现在的目标就是得到 (x) 的子树中能作为 (T_2) 的起始点的点的个数,发现不好进行解决,不妨将其转化为能作为 (T_2) 的起始点的点中 dfn 大于等于 (dfn_x) 小于等于 (end\_dfn_x) 的点的个数。

    于是我们可以这样解决:在插入每个串时,在每个经过的点上增加一个当前剩余的后缀(的 Hash 值),在递归求 dfn 时将每个点上的串与该点的 dfn 结合加入一个序列中,最后将该序列按照先 Hash 值后 dfn 的顺序进行排序,得到的序列中同样的串所在位置连续,于是用 lower_bound()upper_bound() 结合即可得到答案。

    由于不同字符串的数量可能很大,这里采用双 Hash 防止冲突。

    #Code

    #define ll long long
    #define pii pair <int, int>
    #define mkp(a, b) make_pair(a, b)
    
    const int N = 3000010;
    const int BAS1 = 131;
    const int BAS2 = 13331;
    const int MOD1 = 998244353;
    const int MOD2 = 1004535809;
    
    template <typename T> inline void read(T &x) {
        x = 0; int f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }
    
    int dfn[N], endp[N], ch[N][30], cnt = 1;
    int hash_val1[N], hash_val2[N], T;
    
    vector <pii > h[N]; /*the hash values of each string belong the node.*/
    vector <pair <pii, int> > v; /*the list of all hash values with dfn.*/
    
    /*Insert a new string, and add the hash values of 
    the suffixes to the list of corresponding node.*/
    void insert(char *s) {
        int len = strlen(s), p = 1;
        hash_val1[len] = hash_val2[len] = 0;
        /*Get the hash value of each suffix.*/
        for (int i = len - 1; ~i; -- i)
          hash_val1[i] = (1ll * hash_val1[i + 1] * BAS1 % MOD1 + s[i] - 96) % MOD1,
          hash_val2[i] = (1ll * hash_val2[i + 1] * BAS2 % MOD2 + s[i] - 96) % MOD2;
        h[p].push_back(mkp(hash_val1[0], hash_val2[0]));
        /*Insert string and add the hash values.*/
        for (int i = 0; i < len; ++ i) {
            int k = s[i] - 96;
            if (!ch[p][k]) {ch[p][k] = ++ cnt;} p = ch[p][k];
            h[p].push_back(mkp(hash_val1[i + 1], hash_val2[i + 1]));
        }
    }
    
    
    /*Get the dfn of each node, and add the hash
    values with dfn to the list at the same time.*/
    void dfs(int x) {
        dfn[x] = ++ T;
        for (auto i : h[x]) v.push_back(mkp(mkp(i.first, i.second), T));
        for (int i = 1; i <= 26; ++ i) if (ch[x][i]) dfs(ch[x][i]);
        endp[x] = T;
    }
    
    int n, m; char a[N];
    
    int main() {
        read(n); read(m); 
        for (int i = 1; i <= n; ++ i)
          scanf("%s", a), insert(a);
        dfs(1); sort(v.begin(), v.end());
        while (m --) {
            scanf("%s", a); int l = strlen(a), p = 1, q = 0;
            /*Get into the end node of T1.*/
            while (q < l && a[q] != '*') p = ch[p][a[q] - 96], ++ q;
            /*Get the hash value of T_2.*/
            int hv1 = 0, hv2 = 0;
            for (int i = l - 1; i > q; -- i)
              hv1 = (1ll * hv1 * BAS1 % MOD1 + a[i] - 96) % MOD1,
              hv2 = (1ll * hv2 * BAS2 % MOD2 + a[i] - 96) % MOD2;
            printf("%d
    ", ub(mkp(mkp(hv1, hv2), endp[p])) - lb(mkp(mkp(hv1, hv2), dfn[p])));
        }
        return 0;
    }
    

    囸,当时在被 whk 蹂躏,不知道有 extra Round...

  • 相关阅读:
    【ThreadX】Azure RTOS ThreadX概述
    -- spi flash 擦除接口调用HAL库不同函数的区别
    STM32 芯片锁死解决方法
    【KEIL】User's Guide
    【KEIL】Software Packs
    【KEIL 】Options for File
    使用CubeMX创建TouchGFX工程时LCD死活不显示
    【转】获取本地图片的URL
    printf 函数格式控制
    【集成】touchgfx 之 《Using C code with TouchGFX》
  • 原文地址:https://www.cnblogs.com/Dfkuaid-210/p/ZROI-21-CSP-EXTRA1.html
Copyright © 2020-2023  润新知