zoukankan      html  css  js  c++  java
  • LOJ #6074. 「2017 山东一轮集训 Day6」子序列

    #6074. 「2017 山东一轮集训 Day6」子序列

    分析:

      首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j。于是有转移方程:

    $$ f_{i,j}= egin{cases} f_{i-1,j}&,j eq S_i\ sum_{k=1}^{m+1}f_{i-1,k}&,j=S_i end{cases} $$

      表示如果当前j不是s[i]的话,最靠后的结尾的j还是那个位置,从i-1转移即可,否则,最靠后的s[i]变成i这个位置,于是加上前面所有最靠后出现的字符即可(即从i往前走到k,如果s[k]在k+1~i之间没有s[k]了,就加上)。

      这个dp还有一个形象的解释:每个i向它后面第一个出现的字符连有向边(即如果i->j有边,那么i+1~j之间没有s[[j]),然后DAG上的路径数就是答案。

      然后可以对每个位置求一个$10 imes 10$的转移矩阵$A_i$,$F_i$是一个$10 imes 1$的矩阵,有$F_i = A_i imes F_{i - 1}$。

      于是可以分别维护矩阵的前缀积,和逆矩阵的前缀积。

      然后复杂度可以做到$nc^3+qc^2$,由于这个矩阵的性质,可以$nc^2$预处理,所以可以做到$nc^2+qc^2$,至于如何做到$nc+qc$,可以看这

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    #include<bitset>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 100005, mod = 1e9 + 7;
    struct Matrix{ int a[10][10]; Matrix() { memset(a, 0, sizeof(a)); } } s1[N], s2[N];
    char str[N];
    int s[N], tmp[15];
    
    inline void add(int &x,int y) { x += y; if (x >= mod) x -= mod; }
    inline void sub(int &x,int y) { x -= y; if (x < 0) x += mod; }
    void init(int n) {
        for (int i = 0; i < 10; ++i) s1[0].a[i][i] = s2[0].a[i][i] = 1;
        for (int i = 0; i < 10; ++i) s1[1].a[i][i] = 1;
        for (int i = 0; i < 10; ++i) s1[1].a[s[1]][i] = 1;
        for (int i = 2; i <= n; ++i) {
            s1[i] = s1[i - 1];
            for (int j = 0; j < 10; ++j) tmp[j] = 0;
            for (int j = 0; j < 10; ++j) 
                for (int k = 0; k < 10; ++k) add(tmp[j], s1[i - 1].a[k][j]);
            for (int j = 0; j < 10; ++j) s1[i].a[s[i]][j] = tmp[j];
        }
        for (int i = 0; i < 10; ++i) s2[1].a[s[1]][i] = mod - 1;
        for (int i = 0; i < 10; ++i) s2[1].a[i][i] = 1;
        for (int i = 2; i <= n; ++i) {
            s2[i] = s2[i - 1];
            for (int j = 0; j < 10; ++j) for (int k = 0; k < 10; ++k) if (k != s[i]) sub(s2[i].a[j][k], s2[i - 1].a[j][s[i]]);
        }
    }
    int main() {
        scanf("%s", str + 1);
        int n = strlen(str + 1);
        for (int i = 1; i <= n; ++i) s[i] = str[i] - 'a';
        init(n);
        for (int m = read(); m --; ) {
            int l = read(), r = read();
            for (int i = 0; i < 10; ++i) tmp[i] = 0; 
            for (int i = 0; i < 10; ++i) add(tmp[i], s2[l - 1].a[i][9]);
            int sum = 0;
            for (int i = 0; i < 10; ++i) 
                for (int j = 0; j < 10; ++j) 
                    add(sum, 1ll * s1[r].a[i][j] * tmp[j] % mod);            
            cout << (sum - 1 + mod) % mod << "
    ";
         }
        return 0;
    }
  • 相关阅读:
    JavaScript Date 对象
    javascript Array类型 方法大全
    Flexbox
    CSS 去除浏览器默认 轮廓外框
    多行文本溢出显示省略号(…) text-overflow: ellipsis
    最全CSS3选择器
    何时使用 Em 与 Rem
    前端笔试面试题
    oracle中 lob类型
    MySQL 5.5.62 安装方法(标准配置版)
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10618319.html
Copyright © 2011-2022 走看看