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;
}
View Code

 

以上是关于2019.01.19-2018年6月NEYC集训sequence的主要内容,如果未能解决你的问题,请参考以下文章

2022年ACM暑假集训个人排位赛A-F题解

2022年ACM暑假集训个人排位赛A-F题解

「6月雅礼集训 2017 Day11」tree

「6月雅礼集训 2017 Day10」quote

「6月雅礼集训 2017 Day11」jump

「6月雅礼集训 2017 Day8」gcd