题目链接

思路

首先考虑暴力\(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. 001. Java内存中的字符编码

    Java内存中的字符编码 Unicode字符集及utf-8 .utf-16.utf-32 等字符编码方式 字符集:字符表示的数字集合,元素称为码点或码位: 字符编码:字符实际的储存表示: 码点:一个码 ...

  2. Spring MVC(四)文件上传

    文件上传步骤 1.写一个文件上传的页面 2.写一个文件上传的控制器 注意: 1.method="post" 2.enctype="multipart/form-data& ...

  3. Ant Design按需加载

    不eject情况下配置antd按需加载 1.安装 react-app-rewired yarn add react-app-rewired 2. 项目根目录下新建 config-overrides.j ...

  4. NET4.6下的UTC时间转换

    int UTCSecond = (int)((DateTimeOffset)DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local)).ToUnix ...

  5. vue build报copy-webpack-plugin] unable to locate异常的解决方法

    ERROR in [copy-webpack-plugin] unable to locate 'J:\xxx\xxx\xxx\xxx\static' at 'J:\xxx\xxx\xxx\xxx\s ...

  6. SQL 行转列 PIVOT 学习示例

    CREATE TABLE [StudentScores] ( ), --学生姓名 ), --科目 [Score] FLOAT, --成绩 ) select * from [StudentScores] ...

  7. RPM-GPG-KEY详解

    GPG在Linux上的应用主要是实现官方发布的包的签名机制 GPG分为公钥及私钥 公钥:顾名思意,即可共享的密钥,主要用于验证私钥加密的数据及签名要发送给私钥方的数据 私钥:由本地保留的密钥,用于签名 ...

  8. Zabbix3.4-RHEL 7.4 X64 YUM联网安装

    OS准备 关闭selinux vi /etc/selinux/config setenforce 0 开启防火墙80端口访问 firewall-cmd --permanent --add-rich-r ...

  9. Hybrid APP之Native和H5页面交互原理

    Hybrid APP之Native和H5页面交互原理 Hybrid APP的关键是原生页面与H5页面直接的交互,如下图,痛过JSBridge,H5页面可以调用Native的api,Native也可调用 ...

  10. Codeforces #541 (Div2) - E. String Multiplication(动态规划)

    Problem   Codeforces #541 (Div2) - E. String Multiplication Time Limit: 2000 mSec Problem Descriptio ...