zoukankan      html  css  js  c++  java
  • LOJ子序列

    题目描述

    https://loj.ac/problem/6074

    题解

    对于子序列的dp,我们可以设置一个dp。

    我们设dp[i]表示以i这个字符结尾的子序列个数,转移为dp[i]+=∑dp[k]-dp[i]。其实我们发现这样等价于dp[i]=∑dp[k]。

    另外我们还要再设一个空字符的位置表示空字符,所以我们的转移矩阵长成这样。

    1 0 1 0 0 

    0 1 1 0 0 

    0 0 1 0 0

    0 0 1 1 0

    0 0 1 0 1

    我们一开始是空的,所以转移矩阵为

    0 0 0 0 1

    最后我们要归为一个答案,所以还要乘上一个列矩阵。

    1

    1

    1

    1

    0

    直接做是N^3的,我们发现这个矩阵长得非常有特点,我们把它的逆矩阵求出来之后发现。

    1 0 -1 0 0

    0 1 -1 0 0

    0 0 1 0 0

    0 0 -1 1 0

    0 0 -1 0 1

    所以我们的思路就是让行向量*1~l-1的逆矩阵再乘上1~r的正矩阵,在乘上列矩阵。

    对于正矩阵和逆矩阵的部分我们可以分开维护。

    对于正矩阵的右乘的过程,我们可以维护每一行的和,因为每次的乘法相当于把ch位变成这一行的和,所以就直接维护就好了。

    注意我们维护的是最后做完之后再乘上一个列矩阵,所以维护的时候只需要维护矩阵和矩阵乘列向量的值就好了。

    对于逆矩阵的左乘,我们考虑它实际上是把当前列的第ch位减掉,而且它是对每个列除了ch行都批量的减掉,所以我们维护一下每一列的加法标记就好了。

    同样我们也是要维护乘完之后再去乘上行向量的答案。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define M 11
    #define N 100002
    using namespace std;
    const int mod=1e9+7;
    char s[N];
    int sum[M],n,c,now[M][M],val[N],nowl[N][M],nowr[N][M],tag[M];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);
        c=10;
        for(int i=0;i<=c;++i)sum[i]=1,nowr[0][i]=1,now[i][i]=1;
        nowr[0][c]=0;
        for(int i=1;i<=n;++i){
            int x=s[i]-'a';
            for(int j=0;j<=c;++j)
               val[j]=now[j][x],now[j][x]=sum[j];
            for(int j=0;j<=c;++j)sum[j]=(1ll*sum[j]*2-val[j]+mod)%mod;
            for(int j=0;j<=c;++j)nowr[i][j]=(1ll*sum[j]-now[j][c]+mod)%mod;
        }
        nowl[0][c]=1;
        memset(now,0,sizeof(now));
        for(int i=0;i<=c;++i)now[i][i]=1;
        for(int i=1;i<=n;++i){
            int x=s[i]-'a';
            for(int j=0;j<=c;++j)val[j]=(now[x][j]+tag[j])%mod;
            for(int j=0;j<=c;++j)now[x][j]=(now[x][j]+val[j])%mod,tag[j]=(tag[j]-val[j]+mod)%mod;
            for(int j=0;j<=c;++j)nowl[i][j]=(now[c][j]+tag[j])%mod;
        }
        int q=rd();int l,r;
        while(q--){
            l=rd();r=rd();int ans=0;
            for(int i=0;i<=c;++i)(ans+=1ll*nowr[r][i]*nowl[l-1][i]%mod)%=mod;
            printf("%d
    ",ans); 
        }
        return 0;
    }
  • 相关阅读:
    前台js的复制与粘贴
    idea
    前台 js easyUI datagrid 杂记 验证(disable)
    《命运赋》
    前台
    js 、 java去除字符串中的数字
    【 协议 】 freemodbus的分层结构分析
    王爽 汇编11.10(2)编程用串传送指令,将F000H段中最后的16个字节复制到data段中
    王爽 汇编11.10(1)编程用串传送指令,将data段中的第一个字符串赋值到它后面的空间中
    汇编语搜索言中32位CPU多出的两个FS、GS段寄存器,全称是什么啊?
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10481070.html
Copyright © 2011-2022 走看看