JZOJ 5132 子序列

来源:互联网 发布:奥地利 知乎 编辑:程序博客网 时间:2024/06/15 05:37

子序列

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

考虑如何求一个序列的本质不同的子序列个数,有一个简单的DP
F[i][j]表示序列前i个位置以第j个字母结尾的本质不同的子序列个数。(j9)
S[i]=p,则F[i][p]=F[i-1][k]+1F[i][r]=F[i-1][r](rp)。

上述的状态转移方程可以视为一个矩阵,第i个位置的转移方程都对应一个矩阵Ai,对于每个询问(l,r)的答案可以由Al * Al+1 * …… * Ar1 * Ar求得,但这样显然会超时,所以我们考虑求出Ai的逆矩阵Bi,并分别预处理出矩阵前缀积T以及逆矩阵前缀积W,易知Wi=Bi * Wi1Ti=Ti1 * Ai
那么对于每个询问只需算出Wl1*Tr即可求解。

Code

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#define fo(i,j,l) for(i=j;i<=l;i++)#define fd(i,j,l) for(i=j;i>=l;i--)using namespace std;typedef long long ll;const ll N=120000,mo=1000000007,W=11;char s[N];int i,len,j,ak,o=0,l,p,n,q,zb,rr;int dy[26];ll zqz[N][W][W],nqz[N][W][W];ll jz[W][W][W],nj[W][W][W];ll k1[W][W],k2[W][W],k3[W][W];void xc(){    int i,j,l;    fo(i,1,o) fo(l,1,o){        k3[i][l]=0;        fo(j,1,o)k3[i][l]+=k1[i][j]*k2[j][l];        k3[i][l]=k3[i][l]%mo;    }}void tj(int pp,int w){    int i,l;    fo(i,1,o) fo(l,1,o) k1[i][l]=zqz[pp-1][i][l],k2[i][l]=jz[w][i][l];    xc();    fo(i,1,o) fo(l,1,o) zqz[pp][i][l]=k3[i][l];    fo(i,1,o) fo(l,1,o) k2[i][l]=nqz[pp-1][i][l],k1[i][l]=nj[w][i][l];    xc();    fo(i,1,o) fo(l,1,o) nqz[pp][i][l]=k3[i][l];}int main(){    scanf("%s",s+1);    n=strlen(s+1);    fo(i,1,n)    if(!dy[s[i]-'a'])dy[s[i]-'a']=++o;    o++;     fo(i,1,o-1)    fo(l,1,o)jz[i][l][l]=1,jz[i][i][l]=1;    fo(i,1,o-1) fo(l,1,o)   nj[i][l][l]=1;    fo(i,1,o-1) fo(l,1,o) if(i!=l) nj[i][i][l]=mo-1;    fo(i,1,o)zqz[0][i][i]=1,nqz[0][i][i]=1;    fo(i,1,n)tj(i,dy[s[i]-'a']);    scanf("%d",&q);    fo(i,1,q)    {        scanf("%d%d",&zb,&rr);        fo(l,1,o)fo(j,1,o)k1[l][j]=nqz[zb-1][l][j],k2[l][j]=zqz[rr][l][j];        xc(); ll ans=0;         fo(l,1,o-1)ans=(ans+k3[l][o])%mo;        printf("%lld\n",ans);    }}