省队集训DAY6

T1

省队集训DAY6_第1张图片
省队集训DAY6_第2张图片

题解

f[i]表示以字符i结尾的字符串的个数。
那么现在加入一个字符产生的贡献就是 i=0f[i] ,然后把这个答案赋值给这个字符对应的位置。
考虑这么做会不会产生相同的串?假设acbb,考虑插入第一个b的影响会形成ab,cb,acb.那么插入第二个b会形成abb,cbb,acbb发现这些都是新产生的不会与之前的相同,而且不会影响到a,c结尾的字符串。
那么每次转移实际上是乘上了一个对角线为1,某一列为1为1的矩阵。
我们可以维护矩阵的前缀积,和逆矩阵的前缀积。
那么对于每次询问都可以看成是两个矩阵相乘。
因为矩阵是没有交换率的,所以正矩阵维护成 A1,A2,A3... 的形式
对于逆矩阵,我们要保证 Inv3,Inv2,Inv1 顺次与A中对应的矩阵相乘。所以每次更新的时候是 Inv[i]=mul(rs[x],Inv[i1]),rs[i] 表示字符x的逆矩阵。
Inv3Inv2Inv1A1A2A3 这样顺次相消。
如何求一个矩阵的逆矩阵?
什么是逆矩阵? AA1=E 其中E表示单位矩阵,那么 A1 A 的逆矩阵。
首先将逆矩阵赋值为单位矩阵,然后对A进行高斯消元,将A矩阵变成单位矩阵,变换过程中对A矩阵的所有操作都在逆矩阵中同等实现。做完后的逆矩阵即为所求。
如果最后无法消成单位矩阵,那么说明该矩阵不存在逆矩阵。

代码

#include
#include
#include
#include
#include
#define N 10
#define p 1000000007
#define LL long long 
using namespace std;
struct data{
    LL a[N+3][N+3];
}base[N+3],inv[N+3],ans,sum[100003],sinv[100003];
int n,m; char s[100003];
data mul(data a,data b)
{
    data c; 
    for (int i=1;i<=N;i++)
     for (int j=1;j<=N;j++) {
        c.a[i][j]=0;
        for (int k=1;k<=N;k++)
         c.a[i][j]=c.a[i][j]+a.a[i][k]*b.a[k][j];
        c.a[i][j]%=p;
     }
    return c;
}
LL quickpow(LL num,int x)
{
    LL ans=1,base=num%p;
    while (x) {
        if (x&1) ans=ans*base%p;
        x>>=1;
        base=base*base%p;
    }
    return ans;
}
void guass(data a,data &inv)
{
    for (int i=1;i<=N;i++) inv.a[i][i]=1;
    for (int i=1;i<=N;i++) {
        int num=i;
        for (int j=i+1;j<=N;j++)
         if (abs(a.a[j][i])>abs(a.a[num][i])) num=j;
        if (num!=i) {
            for (int j=1;j<=N;j++)
             swap(a.a[i][j],a.a[num][j]),
             swap(inv.a[i][j],inv.a[num][j]);
        }
        LL t=quickpow(a.a[i][i],p-2);
        for (int j=1;j<=N;j++){
            a.a[i][j]=a.a[i][j]*t%p;
            inv.a[i][j]=inv.a[i][j]*t%p;
        }
        for (int j=1;j<=N;j++)
         if (i!=j&&a.a[j][i]) {
            t=a.a[j][i];
            for (int k=1;k<=N;k++){
                a.a[j][k]=(a.a[j][k]-a.a[i][k]*t%p)%p;
                inv.a[j][k]=(inv.a[j][k]-inv.a[i][k]*t%p)%p;
             }
         }
    }
}
int main()
{
    freopen("sub.in","r",stdin);
    freopen("sub.out","w",stdout);
    scanf("%s",s+1); 
    n=strlen(s+1);
    for (int t=1;t<=9;t++) {
        for (int i=1;i<=N;i++) base[t].a[i][i]=1;
        for (int i=1;i<=N;i++) base[t].a[i][t+1]=1;
        guass(base[t],inv[t]);
    }
    ans.a[1][1]=1;
    for (int i=1;i<=N;i++) sinv[0].a[i][i]=1;
    sum[1]=base[s[1]-'a'+1];
    sinv[1]=inv[s[1]-'a'+1];
    for (int i=2;i<=n;i++)
     sum[i]=mul(sum[i-1],base[s[i]-'a'+1]),
     sinv[i]=mul(inv[s[i]-'a'+1],sinv[i-1]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++) {
        int l,r; scanf("%d%d",&l,&r);
        LL ck=0;
        for (int j=1;j<=N;j++)
         for (int k=1;k<=N;k++) 
          ck=(ck+sinv[l-1].a[1][j]*sum[r].a[j][k]%p)%p;
        printf("%I64d\n",(ck+p-1)%p); 
    }

}

你可能感兴趣的:(省队集训DAY6)