#6074. 「2017 山东一轮集训 Day6」子序列

分析:

  首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j。于是有转移方程:

$$ f_{i,j}= \begin{cases} f_{i-1,j}&,j\neq S_i\\ \sum_{k=1}^{m+1}f_{i-1,k}&,j=S_i \end{cases} $$

  表示如果当前j不是s[i]的话,最靠后的结尾的j还是那个位置,从i-1转移即可,否则,最靠后的s[i]变成i这个位置,于是加上前面所有最靠后出现的字符即可(即从i往前走到k,如果s[k]在k+1~i之间没有s[k]了,就加上)。

  这个dp还有一个形象的解释:每个i向它后面第一个出现的字符连有向边(即如果i->j有边,那么i+1~j之间没有s[[j]),然后DAG上的路径数就是答案。

  然后可以对每个位置求一个$10 \times 10$的转移矩阵$A_i$,$F_i$是一个$10 \times 1$的矩阵,有$F_i = A_i \times F_{i - 1}$。

  于是可以分别维护矩阵的前缀积,和逆矩阵的前缀积。

  然后复杂度可以做到$nc^3+qc^2$,由于这个矩阵的性质,可以$nc^2$预处理,所以可以做到$nc^2+qc^2$,至于如何做到$nc+qc$,可以看这

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = , mod = 1e9 + ;
struct Matrix{ int a[][]; Matrix() { memset(a, , sizeof(a)); } } s1[N], s2[N];
char str[N];
int s[N], tmp[]; inline void add(int &x,int y) { x += y; if (x >= mod) x -= mod; }
inline void sub(int &x,int y) { x -= y; if (x < ) x += mod; }
void init(int n) {
for (int i = ; i < ; ++i) s1[].a[i][i] = s2[].a[i][i] = ;
for (int i = ; i < ; ++i) s1[].a[i][i] = ;
for (int i = ; i < ; ++i) s1[].a[s[]][i] = ;
for (int i = ; i <= n; ++i) {
s1[i] = s1[i - ];
for (int j = ; j < ; ++j) tmp[j] = ;
for (int j = ; j < ; ++j)
for (int k = ; k < ; ++k) add(tmp[j], s1[i - ].a[k][j]);
for (int j = ; j < ; ++j) s1[i].a[s[i]][j] = tmp[j];
}
for (int i = ; i < ; ++i) s2[].a[s[]][i] = mod - ;
for (int i = ; i < ; ++i) s2[].a[i][i] = ;
for (int i = ; i <= n; ++i) {
s2[i] = s2[i - ];
for (int j = ; j < ; ++j) for (int k = ; k < ; ++k) if (k != s[i]) sub(s2[i].a[j][k], s2[i - ].a[j][s[i]]);
}
}
int main() {
scanf("%s", str + );
int n = strlen(str + );
for (int i = ; i <= n; ++i) s[i] = str[i] - 'a';
init(n);
for (int m = read(); m --; ) {
int l = read(), r = read();
for (int i = ; i < ; ++i) tmp[i] = ;
for (int i = ; i < ; ++i) add(tmp[i], s2[l - ].a[i][]);
int sum = ;
for (int i = ; i < ; ++i)
for (int j = ; j < ; ++j)
add(sum, 1ll * s1[r].a[i][j] * tmp[j] % mod);
cout << (sum - + mod) % mod << "\n";
}
return ;
}

LOJ #6074. 「2017 山东一轮集训 Day6」子序列的更多相关文章

  1. loj#6074. 「2017 山东一轮集训 Day6」子序列(矩阵乘法 dp)

    题意 题目链接 Sol 设\(f[i][j]\)表示前\(i\)个位置中,以\(j\)为结尾的方案数. 转移的时候判断一下\(j\)是否和当前位置相同 然后发现可以用矩阵优化,可以分别求出前缀积和逆矩 ...

  2. loj#6076「2017 山东一轮集训 Day6」三元组 莫比乌斯反演 + 三元环计数

    题目大意: 给定\(a, b, c\),求\(\sum \limits_{i = 1}^a \sum \limits_{j = 1}^b \sum \limits_{k = 1}^c [(i, j) ...

  3. LOJ#6075. 「2017 山东一轮集训 Day6」重建

    题目描述: 给定一个 n个点m 条边的带权无向连通图 ,以及一个大小为k 的关键点集合S .有个人要从点s走到点t,现在可以对所有边加上一个非负整数a,问最大的a,使得加上a后,满足:s到t的最短路长 ...

  4. 「2017 山东一轮集训 Day6」子序列(矩阵快速幂)

    /* 找出了一个dp式子 是否能够倍增优化 我推的矩阵不太一样 是 1 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 1 0 0 1 0 0 2 求得逆矩阵大概就是 1 0 0 ...

  5. Loj #6069. 「2017 山东一轮集训 Day4」塔

    Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...

  6. Loj #6073.「2017 山东一轮集训 Day5」距离

    Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...

  7. Loj 6068. 「2017 山东一轮集训 Day4」棋盘

    Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...

  8. loj #6077. 「2017 山东一轮集训 Day7」逆序对

    #6077. 「2017 山东一轮集训 Day7」逆序对   题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...

  9. LOJ #6119. 「2017 山东二轮集训 Day7」国王

    Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...

随机推荐

  1. 理解ES6中的Promise

    一.Promise的作用 在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理. 这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这 ...

  2. vmare连接远程服务器的问题

    测试环境:两端都是VMware Workstation 12 Pro 1.需要共享虚拟机 在虚拟机上点击右键 -> Manage -> Share 后面按照操作设置 2.远程服务器的443 ...

  3. URL编码:怎样读取特殊字符

    URL编码:怎样读取特殊字符 (这个我曾经谢过教程,这里整理过来)从外部文本载入到动态文本的时候,一些特殊字符(如&/%等)无法正常现实,有的符号还会导致这个符号后面的字符无法现实(如& ...

  4. Arch Linux 更新源(以清华 arch 源为例)

    Arch Linux 编辑­/etc/pacman.d/mirrorlist,在文件最顶端添加: Server = https://mirrors.tuna.tsinghua.edu.cn/archl ...

  5. Gogs基本使用介绍

    Gogs简介 Gogs 是一款类似GitHub的开源文件/代码管理系统(基于Git),Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs ...

  6. Activity总结

    1)Activity在app构建中的位置: 2)与window和视图体系.事件处理的关系: 3)生命周期: 4)启动方式: 5)activity管理: 6)加载管理:

  7. 如何在sublime编辑器中,执行命令行脚本

    我有个愿意,在执行命令行时,不打开那个黑乎乎命令行窗口,如果编辑器内置支持就好了. 打开vs code 和 sublime,分别按快捷键 Ctrl + ·(tab键上面那个键),vs code可以提供 ...

  8. UVA127-"Accordian" Patience(模拟)

    Problem UVA127-"Accordian" Patience Accept:3260  Submit:16060 Time Limit: 3000 mSec Proble ...

  9. bzoj5093:[Lydsy1711月赛]图的价值

    题目 首先考虑到这是一张有标号的图,每一个点的地位是相等的,因此我们只需要求出一个点的价值和乘上\(n\)就好了 考虑一个点有多少种情况下度数为\(i\) 显然我们可以让除了这个点的剩下的\(n-1\ ...

  10. MySQL慢查询1- 开启慢查询

    本文章摘自网络,学习之用 一.简介 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能. 二.参数说明 slow_query_log ...