• CF645E Intellectual Inquiry


    CF645E Intellectual Inquiry

    给一个长为 (m) 的字符串 (S) ,你需要用第 (1)(k) 个小写字母构造一个长为 (n) 的字符串 (S') ,使得 (S+S') 本质不同的子串个数最多

    输出子串个数 (pmod {10^9+7})

    (n, mleq10^6, kleq26)

    动态规划,贪心


    考虑如何求出一个串本质不同的子串个数

    设计一个线性dp,令 (f_i)(S)(i) 位所构成的子串个数

    (i) 位有取或不取两种状态,因此若不考虑去重, (f_i=2f_{i-1})

    若选取第 (i) 位,计算重复的部分为以这个字符上一次出现的位置为结尾的子串个数(想一想,为什么)

    综上所述 (f_i=2f_{i-1}-f_{lst_i-1})

    对于构造字符串 (S') ,显然要让 (f_{lst_i-1}) 尽量小,由于 (f_i) 单调递增,于是只需让 (lst_i) 尽量小即可,可以用堆维护(实际上直接暴力 (O(k)) 常数还小一点

    时间复杂度 (O(nlog k))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef pair <int, int> pii;
    const int maxn = 1e6 + 10, P = 1e9 + 7;
    char str[maxn];
    int n, m, k, lst[26], dp_buf[maxn << 1], *f = dp_buf + 1;
    
    inline int add(int a, int b) {
      a += b; return a < P ? a : a - P;
    }
    
    inline int dec(int a, int b) {
      a -= b; return a < 0 ? a + P : a;
    }
    
    int main() {
      scanf("%d %d %s", &n, &k, str + 1);
      m = strlen(str + 1);
      f[0] = 1;
      for (int i = 1; i <= m; i++) {
        f[i] = dec(add(f[i - 1], f[i - 1]), f[lst[str[i] - 'a'] - 1]);
        lst[str[i] - 'a'] = i;
      }
      static priority_queue <int, vector <int>, greater <int> > Q;
      for (int i = 0; i < k; i++) {
        Q.push(lst[i]);
      }
      for (int i = m + 1; i <= n + m; i++) {
        int p = Q.top(); Q.pop();
        f[i] = dec(add(f[i - 1], f[i - 1]), f[p - 1]);
        Q.push(i);
      }
      printf("%d", f[n + m]);
      return 0;
    }
    
  • 相关阅读:
    [windows] gcc编译器
    [windos] 命令
    软件版本命名规范
    [linux] vim 编辑器---更改注释文字颜色
    Call Indels/SV常用软件-搬运工
    [生物信息比对软件列表]
    [samtools] 文本查看语法,浏览SNP/INDEL位点
    [python] 之 异常对象
    [python] 之 类-运算符重载
    [R] 之 管理工作空间函数
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10960489.html
Copyright © 2020-2023  润新知