省队集训DAY6

本文介绍了一种使用矩阵乘法和前缀积技巧解决字符串匹配问题的方法,并提供了详细的算法步骤及其实现代码。通过构建特定矩阵及其逆矩阵,可以有效地处理字符串的动态变化,解决了在动态字符串上快速查询子串出现次数的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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[i1]),rs[i]表示字符x的逆矩阵。
Inv3Inv2Inv1A1A2A3这样顺次相消。
如何求一个矩阵的逆矩阵?
什么是逆矩阵?AA1=E其中E表示单位矩阵,那么A1A的逆矩阵。
首先将逆矩阵赋值为单位矩阵,然后对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); 
    }

}
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在 IT 领域,文档格式转换是常见需求,尤其在处理多种文件类型时。本文将聚焦于利用 Java 技术栈,尤其是 Apache POI 和 iTextPDF 库,实现 doc、xls(涵盖 Excel 2003 及 Excel 2007+)以及 txt、图片等格式文件向 PDF 的转换,并实现在线浏览功能。 先从 Apache POI 说起,它是一个强大的 Java 库,专注于处理 Microsoft Office 格式文件,比如 doc 和 xls。Apache POI 提供了 HSSF 和 XSSF 两个 API,其中 HSSF 用于读写老版本的 BIFF8 格式(Excel 97-2003),XSSF 则针对新的 XML 格式(Excel 2007+)。这两个 API 均具备读取和写入工作表、单元格、公式、样式等功能。读取 Excel 文件时,可通过创建 HSSFWorkbook 或 XSSFWorkbook 对象来打开相应格式的文件,进而遍历工作簿中的每个 Sheet,获取行和列数据。写入 Excel 文件时,创建新的 Workbook 对象,添加 Sheet、Row 和 Cell,即可构建新 Excel 文件。 再看 iTextPDF,它是一个用于生成和修改 PDF 文档的 Java 库,拥有丰富的 API。创建 PDF 文档时,借助 Document 对象,可定义页面尺寸、边距等属性来定制 PDF 外观。添加内容方面,可使用 Paragraph、List、Table 等元素将文本、列表和表格加入 PDF,图片可通过 Image 类加载插入。iTextPDF 支持多种字体和样式,可设置文本颜色、大小、样式等。此外,iTextPDF 的 TextRenderer 类能将 HTML、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值