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[i−1]),rs[i]
表示字符x的逆矩阵。
Inv3∗Inv2∗Inv1∗A1∗A2∗A3
这样顺次相消。
如何求一个矩阵的逆矩阵?
什么是逆矩阵?
A∗A−1=E
其中E表示单位矩阵,那么
A−1
是
A
<script type="math/tex" id="MathJax-Element-8">A</script>的逆矩阵。
首先将逆矩阵赋值为单位矩阵,然后对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);
}
}