题目链接

思路

首先考虑暴力\(dp\)

用\(f[i][j]\)表示前\(i\)个字符,以\(j\)这个字符结尾的本质不同的字符串个数。

然后就有如下的转移

\(if(s_i==j)\)

$$f_{ij}=\sum\limits_{i=1}^9f_{i-1j} + 1$$

\(else\)

$$f_{ij}=f_{i-1j}$$

然后就尝试一下用矩阵转移

对于第\(i\)位置,设一个\(10 \times 10\)的单位矩阵,将\(s_i\)这一列全都是\(1\)。

为什么是\(10 \times 10\)而不是\(9\times9\)呢?

因为第一个转移里面有个\(+1\)

然后对于每次询问,都将初始的\(1 \times 10\)的矩阵的第\(s_{l-1}\)位和第\(10\)位设成\(1\),其他的都是\(0\)。

然后依次乘上\(l\)~\(r\)的矩阵即可。

然后优化

可以发现,用矩阵转移更慢了。

别慌,我们只要想办法快速的将\(l\)~\(r\)内的矩阵乘起来不就行了。

对于这\(n\)个矩阵先处理一个前缀和。然后只要用前\(r\)个矩阵去除以前\(l - 1\)个矩阵就行了。

怎么除呢??

我们把每个矩阵的逆矩阵也求个前缀和就行了。

PS: 矩阵乘法不满足交换律,注意矩阵相乘的顺序。

代码

/* @Author: wxyww
* @Date: 2019-03-28 20:43:54
* @Last Modified time: 2019-03-29 13:53:49
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 100010,mod = 1e9 + 7;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct node {
int a[11][11];
int n,m;
node() {
memset(a,0,sizeof(a));
}
node(int x) {
n = m = x;
memset(a,0,sizeof(a));
for(int i = 1;i <= x;++i) a[i][i] = 1;
}
node(int x,int y) {
n = x,m = y;
memset(a,0,sizeof(a));
}
}tmp1[N],tmp2[N];
char S[N];
int n,s[N];
node operator * (const node &A,const node &B) {
int n = A.n,m = B.n,K = A.m;
node ret(n,m);
for(int k = 1;k <= K;++k) {
for(int i = 1;i <= n;++i) {
for(int j = 1;j <= m;++j) {
ret.a[i][j] += 1ll * A.a[i][k] * B.a[k][j] % mod;
ret.a[i][j] %= mod;
}
}
}
return ret;
}
void pre() {
tmp1[0] = tmp2[0] = node(10);
for(int i = 1;i <= n;++i) {
int k = s[i];
tmp1[i] = tmp2[i] = node(10);
for(int j = 1;j <= 10;++j) tmp1[i].a[j][k] = 1,tmp2[i].a[j][k] = mod - 1;
tmp2[i].a[k][k] = 1;
tmp1[i] = tmp1[i] * tmp1[i - 1];
tmp2[i] = tmp2[i - 1] * tmp2[i];
}
}
int main() {
scanf("%s",S + 1);
n = strlen(S + 1);
for(int i = 1;i <= n;++i) s[i] = S[i] - 'a' + 1;
pre();
int m = read();
while(m--) {
node ans(1,10);
int l = read(),r = read();
ans.a[1][10] = 1;
ans = ans * tmp1[r] * tmp2[l - 1];
int anss = 0;
for(int i = 1;i <= 9;++i) anss += ans.a[1][i],anss %= mod;
printf("%d\n",anss);
}
return 0;
} */

loj6074 子序列的更多相关文章

  1. 【LOJ6074】【2017 山东一轮集训 Day6】子序列 DP

    题目描述 有一个由前 \(m\) 个小写字母组成的串 \(S\),有 \(q\) 个询问,每次给你 \(l,r\),问你 \(S_{l\ldots r}\) 有多少个非空子序列. \(m=9,n=\l ...

  2. 用python实现最长公共子序列算法(找到所有最长公共子串)

    软件安全的一个小实验,正好复习一下LCS的写法. 实现LCS的算法和算法导论上的方式基本一致,都是先建好两个表,一个存储在(i,j)处当前最长公共子序列长度,另一个存储在(i,j)处的回溯方向. 相对 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. [LeetCode] Arithmetic Slices II - Subsequence 算数切片之二 - 子序列

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  5. [LeetCode] Is Subsequence 是子序列

    Given a string s and a string t, check if s is subsequence of t. You may assume that there is only l ...

  6. [LeetCode] Wiggle Subsequence 摆动子序列

    A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...

  7. [LeetCode] Increasing Triplet Subsequence 递增的三元子序列

    Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the ar ...

  8. [LeetCode] Distinct Subsequences 不同的子序列

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  9. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

随机推荐

  1. 如何利用GitHub设计一个炫酷的个人网站(含代码)

    1.在开始制作之前我们先预览一下我的网站吧! 1.方式一: 由于是手机版的所以用手机访问下面的链接体验比较好一点: https://tom-shushu.github.io/MyWeb.github. ...

  2. 原生js实例对象方法

    Array中的方法 ☞ toString() // 把数组转换为字符串,使用逗号分隔☞ valueOf() // 返回数组对象本身 ☞ 栈方法(先进后出)ary.push() // 该方法有一个返回值 ...

  3. 关于如何使用xposed来hook微信软件

     安卓端  难点有两个  收款码的生成和到帐监听   需要源码加 2442982910

  4. qt生成二维码

    到官网下载qrencode http://fukuchi.org/works/qrencode/index.html.en qrenc.c不用,这个是测试用的,把config.h.in文件改为conf ...

  5. APICloud Studio2新建应用报错和检出错误

    今天心血来潮,闲暇时间想做个移动应用app,听一哥们说APICloud开发app很方便,就查询了一下,看了之后简直就是热血沸腾,我感觉正是我一直要找的工具 信心满满的开始着手使用,看了一下介绍我选择了 ...

  6. redis -字符串string

    字符串类型是Redis 中最为基础的数据存储类型,它在Redis 中是二进制安全的,该类型可以接收任何格式的数据,  字符串 Value 最多可以容纳的数据长度是521M. 保存: 设置键值. set ...

  7. Serial Splitter 4.2 串口拆分说明

    使用方法 有些设备和程序只能使用COM端口.如果计算机没有COM端口,或者已经被其他应用程序占用,则需要创建虚拟串行端口.在串行分配器中,我们使用虚拟串行端口驱动程序技术,它可以在系统中创建任意数量的 ...

  8. Docker-镜像源加速配置

    Docker官网镜像服务在境外,拉取速度很比较慢,所以我们安装完Docker后一般会切换镜像源,将镜像源切换到国内以此达到加速的目的. 国内比较常用的Docker Hub镜像服务:1.阿里云2.Dao ...

  9. WebApi发布到外网提示404问题

    今天在做微信接口的对接,需要把webApi发布到服务器,放上去的时候,提示404 找了以后,发现了这段代码,粘贴上去就可以用了 在web.config添加如下节点 <system.webServ ...

  10. mysql8.0绿色版安装及mysqldump备份

    1.下载mysql绿色版压缩包https://dev.mysql.com/downloads/mysql/ 2.解压到安装目录后,在根目录创建data文件夹 3.把mysql下的bin目录添加到环境变 ...