省队集训DAY6

来源:互联网 发布:网络购物狂欢节 编辑:程序博客网 时间:2024/05/16 06:43

T1

这里写图片描述
这里写图片描述

题解

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表示单位矩阵,那么A1A的逆矩阵。
首先将逆矩阵赋值为单位矩阵,然后对A进行高斯消元,将A矩阵变成单位矩阵,变换过程中对A矩阵的所有操作都在逆矩阵中同等实现。做完后的逆矩阵即为所求。
如果最后无法消成单位矩阵,那么说明该矩阵不存在逆矩阵。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#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);     }}
原创粉丝点击