题目大意:给一个只包含前9个字符的字符串,q次询问区间本质不同的子序列数。
n
,
q
≤
1
0
5
n,q\le10^5
n,q≤105。
题解:
考虑dp,设dp[i,j]表示前i个数字以j结尾的方案数。假设当前的是数字是c,那么:
d
p
(
i
,
c
)
=
1
+
∑
k
d
p
(
i
−
1
,
k
)
,
e
l
s
e
d
p
(
i
,
j
)
=
d
p
(
i
−
1
,
j
)
dp(i,c)=1+\sum_{k}dp(i-1,k),\mathrm{else\ }dp(i,j)=dp(i-1,j)
dp(i,c)=1+k∑dp(i−1,k),else dp(i,j)=dp(i−1,j)
如果看做矩乘转移,则
A
i
A_i
Ai这个矩阵是
A
i
,
i
=
A
c
,
i
=
1
A_{i,i}=A_{c,i}=1
Ai,i=Ac,i=1,其余位置是0.
其显然有逆矩阵,并且逆矩阵
B
i
B_i
Bi为,
B
i
,
i
=
1
,
B
c
,
i
=
−
1
(
c
̸
=
i
)
B_{i,i}=1,B_{c,i}=-1(c\not=i)
Bi,i=1,Bc,i=−1(c̸=i)。
然后
a
n
s
w
e
r
(
L
,
R
)
\mathrm{answer(L,R)}
answer(L,R)是:
[
1
1
1
…
1
1
]
A
R
A
R
−
1
⋯
A
1
B
1
B
2
⋯
B
L
−
1
[
0
0
.
.
.
0
1
]
\left[\begin{matrix} 1&1&1\dots1&1 \end{matrix}\right] A_RA_{R-1}\cdots A_1B_1B_2\cdots B_{L-1} \left[\begin{matrix} 0\\0\\.\\.\\.\\0\\1 \end{matrix}\right]
[111…11]ARAR−1⋯A1B1B2⋯BL−1⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡00...01⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤
然后你注意到,左乘一个
A
i
A_i
Ai等价于,第c行的每个数字变成其所在列的和。
右乘一个
B
i
B_i
Bi等价于,对于每一行所有不是第c列的数字,都要减去该行的第c列的数字,这个维护一个加法标记即可。
最后左面的那个行向量关心的是A的前缀积的每一列的和,这个已经维护好了;而最右面的那个列向量关心的是B的前缀积的最后一列,这个也可以
O
(
m
)
O(m)
O(m)提取。最后保留前缀积乘以那个向量的结果,就可以
O
(
m
)
O(m)
O(m)的回答每一个询问。
复杂度
O
(
(
n
+
q
)
m
)
O((n+q)m)
O((n+q)m),空间
O
(
m
2
+
n
m
)
O(m^2+nm)
O(m2+nm)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;
char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
inline int inn()
{
int x,ch;while((ch=gc())<'0'||ch>'9');
x=ch^'0';while((ch=gc())>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
char ss[1500000],tt[20];int ssl,ttl;
inline int PC(char c) { return ss[++ssl]=c; }
inline int print(lint x)
{
if(!x) ss[++ssl]='0';
for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
}
inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::PC;using OUTPUT_SPACE::Flush;
const int m=10,M=m+5,N=100010;
int A[M][M],B[M][M],As[M],dlt[M];
int Ap[N][M],Bp[N][M],s[N];char str[N];
int main()
{
scanf("%s",str+1);int n=int(strlen(str+1));
rep(i,1,n) s[i]=str[i]-'a'+1;
rep(i,1,m) A[i][i]=1,As[i]=Ap[0][i]=1;
rep(i,1,n)
{
int c=s[i],Acj;
rep(j,1,m) Acj=A[c][j],A[c][j]=As[j],As[j]+=As[j]-Acj,
(As[j]>=mod?As[j]-=mod:0),(As[j]<0?As[j]+=mod:0);
memcpy(Ap[i],As,sizeof(int)*(m+1));
}
rep(i,1,m) B[i][i]=1,dlt[i]=0,Bp[0][i]=int(i==m);
rep(i,1,n)
{
int c=s[i],t;
rep(j,1,m) t=B[j][c]-dlt[j],(t<0?t+=mod:0),
dlt[j]+=t,(dlt[j]>=mod?dlt[j]-=mod:0),
B[j][c]+=t,(B[j][c]>=mod?B[j][c]-=mod:0);
rep(j,1,m) Bp[i][j]=B[j][m]-dlt[j],(Bp[i][j]<0?Bp[i][j]+=mod:0);
}
for(int q=inn();q;q--)
{
int L=inn(),R=inn();lint ans=mod-1;
#define P(x) (lint)Ap[R][x]*Bp[L-1][x]
ans=ans+P(1)+P(2)+P(3)+P(4)+P(5)+P(6)+P(7),ans%=mod;
ans=ans+P(8)+P(9)+P(10),ans%=mod,print(int(ans));
}
return Flush();
}