2019.01.19-2018年6月NEYC集训sequence
Posted jessie-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019.01.19-2018年6月NEYC集训sequence相关的知识,希望对你有一定的参考价值。
题目描述:
茉优最近研究发现,一个人的想愿能力可以认为是字符串S的一个子串S[l,r],而连接值可以认为是这个子串的本质不同子序列个数。现在她想验证她的结论是否正确,于是她给了你Q个询问,希望你帮她来计算,注意空串也是子序列。
因为茉优已经有一个答案了,所以你只要输出ZQ的值检验即可。
思路:
考虑对于取以字符i为结尾的转移矩阵,是除了单位矩阵外,第一列为都为1,恰好表示除了以i为结尾的情况其他情况都*2.
于是构建出每个字母的转移矩阵,是一个53*53的矩阵,叫它C[i]。
对于每一个询问,答案其实是前Ar个矩阵的乘积,乘上前Al-1个矩阵的逆。
但是由于矩阵不满足交换律,所以我们呢要做这样的预处理。
Ar=Ar-1*Cs[a[r]]
B表示逆矩阵。
Bl=Cs[a[l]]*Bl-1
Ans=一个1*m的矩阵(只有第一位为0)*Bl*Ar
仔细分析可以发现关于B矩阵我们只需要知道第一行每一位数的数值,
A矩阵我们只需要知道每一列的和。
并且由于每个字母转移矩阵的特殊性,计算过程中结果通常只和一行或一列相关,于是每次维护或一列即可,转移时O(53)
总效率就是O(n*53).
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e6+5,p=998244353; char s[N]; int Q,a0,b0,B,q,R,n,tag[55],ans; struct node{ int l[55]; }a[N],b[N],c[55]; il int read(){ int x,f=1;char ch; _(!)ch==‘-‘?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int C(char a){ if(a<=‘Z‘)return a-‘A‘+1; return a-‘a‘+27; } il int mu(int x,int y){ if(x+y>=p)return x+y-p; return x+y; } int main() { scanf(" %s",s+1);n=strlen(s+1); for(int i=0;i<53;i++)c[i].l[i]=a[0].l[i]=1; for(int i=1;i<=n;i++){ int k=C(s[i]); for(int tmp,j=0;j<53;j++){ tmp=c[j].l[k];c[j].l[k]=a[i-1].l[j]; a[i].l[j]=mu(mu(a[i-1].l[j],a[i-1].l[j]),p-tmp); } } for(int i=0;i<53;i++){ for(int j=0;j<53;j++){ c[i].l[j]=0; } c[i].l[i]=1; } b[0].l[0]=1; for(int i=1;i<=n;i++){ int k=C(s[i]); for(int tmp,j=0;j<53;j++){ tmp=mu(c[k].l[j],p-tag[j]);c[k].l[j]=mu(c[k].l[j],tmp); tag[j]=mu(tag[j],tmp);b[i].l[j]=mu(c[0].l[j],p-tag[j]); } } Q=read();a0=read();b0=read();B=read();q=read();R=read(); while(Q--){ int a1,b1,l,r; a1=mu(mu(1ll*B*a0%p,1ll*q*b0%p),mu(ans,R)); b1=mu(mu(1ll*B*b0%p,1ll*q*a0%p),mu(ans,R)); a0=a1;b0=b1;l=a0%n+1;r=b0%n+1; if(l>r)swap(l,r); ans=0; for(int i=0;i<53;i++){ ans=mu(ans,1ll*a[r].l[i]*b[l-1].l[i]%p); } } printf("%d ",ans); return 0; }
以上是关于2019.01.19-2018年6月NEYC集训sequence的主要内容,如果未能解决你的问题,请参考以下文章