题目链接

参考yww的题解。本来不想写来但是他有一些笔误...而且有些地方不太一样就写篇好了。

不知不觉怎么写了这么多...

另外还是有莫队做法的...(虽然可能卡不过)


\(60\)分的\(O(n^2)\)做法就是,令\(f[i]\)表示以\(s[i]\)结尾的不同子序列个数,\(las[c]\)表示\(c\)字符上次出现的位置(没有出现过则为\(-1\)),转移是:$$f[i]=\begin{cases}2f[i-1]+1&,las[s[i]]=-1\2f[i-1]-f[las[s[i]]]&,las[s[i]]\neq-1\end{cases}$$


上面这个做法挺妙的,但是好像没什么优化空间。

考虑另一种DP,令\(f[i][j]\)表示前\(i\)个字符,以字符\(j\)结尾的不同子序列个数。转移为:$$f[i][j]=\begin{cases}f[i-1][j-1]&,j\neq s_i\\sum_{k=0}^mf[i-1][k]&,j=s_i\end{cases}$$

其中字符集是\(0\sim m-1\)(\(m=9\)),特别的令\(f[i][m]\)表示前\(i\)个字符什么也没选的方案数,因为子序列可以从任意位置开始。

这样不会算重,感觉也挺妙的。。(好吧是自己菜)

显然可以用矩阵把转移表示出来。令$$F_i=\left[\begin{matrix}f_{i,1}\f_{i,2}\\vdots\f_{i,m+1}\end{matrix}\right]$$

转移矩阵就是\(A[i][i]=1,A[c][j]=1\ (c=s[i])\)(把单位矩阵\(s[i]\)那一行全设为\(1\))。就是这样子:$$F_i=A_iF_{i-1}\A_i=\left[\begin{matrix}1&&&&\&1&&&\1&1&1&1&1\&&&1&\&&&&1\end{matrix}\right]$$

再考虑一下初始化、最后的求和,令$$\begin{aligned}U&=\left[\begin{matrix}1\1\\vdots\1\end{matrix}\right]\V&=\left[\begin{matrix}0\ 0\ \cdots\ 0\ 1\end{matrix}\right]\end{aligned}$$

\(A_i\)显然有逆矩阵(可以比较容易地写出来)。那么区间\([l,r]\)的答案就是$$\begin{aligned}&UA_rA_{r-1}\cdots A_lV\=&UA_rA_{r-1}\cdots A_1{A_1}{-1}{A_2}{-1}\ldots A_{l-1}V\end{aligned}$$

这里把\(U\)放到了前面,\(V\)放到了后面,都一样,我觉得还是这样方便一些...

需要注意矩阵乘法没有交换律,注意乘的顺序。

所以预处理一个转移矩阵的前缀积\(f_i\)、转移矩阵逆元的前缀积\(g_i\),就可以\(O(m^3)\)回答一次询问了。

预处理\(f_i\)的时候让它和\(U\)乘一下,同理\(g_i\)和\(V\)乘一下,询问就是\(O(m)\)的了。

但是预处理的复杂度还是\(O(nm^3)\)的(但是开O2已经能过了...)。

注意到转移矩阵非常特殊,一个矩阵\(M\)乘上\(A_i\)时,\(M_{s_i,j}'\)是\(A_i\)第\(j\)列元素的和,\(M'\)其它行的元素不变。这样乘\(A_i\)可以做到\(O(m)\)。

同时左乘\(U\)得到的矩阵就是对列求和。

那么我们维护\(f_i\)的时候(乘了\(U\),是个\(1\times n\)的),第\(j\)列的和即\(f_{i,j}\),就是上一次第\(j\)列的和\(*2\)减去\(A_{s_i,j}\),上一次第\(j\)列的和就是\(f_{i-1,j}\)。那么这个转移也是\(O(m)\)的。

同理,\(A_i^{-1}\)大概是这样:$$A_i=\left[\begin{matrix}1&&&&\&1&&&\-1&-1&1&-1&-1\&&&1&\&&&&1\end{matrix}\right]$$

即\(A[i][i]=1,A[c][j]=-1\ (c=s[i],j\neq i)\)(把单位矩阵\(s[i]\)那一行除了\(A_{s[i],s[i]}\)全设为\(-1\))。

一个矩阵乘\(A_i^{-1}\)时,除了\(c=s[i]\)列之外的列\(M_{i,j}\),都会减去\(M_{i,c}\),第\(c\)列的元素不变。维护一个整行减了多少的标记,对\(M_{i,c}\)单点修改一下即可。

注意到假设其中一行是:\(\left[a_1-v\quad a_2-v\quad a_3-v\quad a_4-v\right]\),\(s[i]=3\)时,会变成\(\left[a_1-a_3\quad a_2-a_3\quad (2a_3-v)-a_3\quad a_4-a_3\right]\),也就是对\(3\)单独修改一下,所有数每次会减掉上次那个数,打个标记修改也是\(O(m)\)的了。

维护\(g_i\)时,注意到右乘一个\(V\)就是把矩阵最后一列取出来,直接求即可。同样\(O(m)\)。

那么总复杂度就做到\(O((n+q)m)\)啦。


//263ms	8760K
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rg register
#define mod 1000000007
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
#define Add2(x,y) (x+y>=mod?x+y-mod:x+y)
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+7,M=10;
const LL LIM=6e18; int s[N],f[N][M],g[N][M];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
void Pre(const int n)
{
static int A[M][M],B[M][M],tag[M];
for(int i=0; i<M; ++i) A[i][i]=B[i][i]=f[0][i]=1;
g[0][M-1]=1;
for(rg int i=1; i<=n; ++i)
{
rg int c=s[i];
for(rg int j=0; j<M; ++j)
{
rg int tmp=f[i-1][j]<<1; Mod(tmp);
f[i][j]=Add2(tmp,mod-A[c][j]);
A[c][j]=f[i-1][j];
tmp=B[j][c]<<1, Mod(tmp); rg int tmp2=B[j][c];
g[i][j]=Add2(B[j][M-1],mod-B[j][c]);
B[j][c]=Add2(tmp,mod-tag[j]), tag[j]=tmp2;
}
}
} int main()
{
int n=0;
register char c; while(isalpha(c=gc())) s[++n]=c-'a';
Pre(n);
for(int q=read(); q--; )
{
int l=read()-1,r=read();
LL ans=0;
if(l) for(int i=0; i<M; ++i) ans+=1ll*f[r][i]*g[l][i], ans>=LIM&&(ans%=mod);
else ans=f[r][M-1];
printf("%lld\n",(ans-1)%mod);
} return 0;
}

LOJ.6074.[2017山东一轮集训Day6]子序列(DP 矩阵乘法)的更多相关文章

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

    #6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...

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

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

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

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

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

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

  5. LOJ.6066.[2017山东一轮集训Day3]第二题(树哈希 二分)

    LOJ 被一件不愉快的小事浪费了一个小时= =. 表示自己(OI方面的)智商没救了=-= 比较显然 二分+树哈希.考虑对树的括号序列进行哈希. 那么每个点的\(k\)子树的括号序列,就是一段区间去掉距 ...

  6. LOJ.6060.[2017山东一轮集训Day1/SDWC2018Day1]Set(线性基)

    LOJ BZOJ 明明做过一道(最初思路)比较类似的题啊,怎么还是一点思路没有. 记所有元素的异或和为\(s\),那么\(x_1+x_2=x_1+x_1\ ^{\wedge}s\). \(s\)是确定 ...

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

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

  8. LOJ.6073.[2017山东一轮集训Day5]距离(可持久化线段树 树链剖分)

    题目链接 就是恶心人的,简单写写了...(似乎就是[HNOI2015]开店?) 拆式子,记\(dis_i\)为\(i\)到根节点的路径权值和,\(Ans=\sum dis_{p_i}+\sum dis ...

  9. LOJ.6068.[2017山东一轮集训Day4]棋盘(费用流zkw)

    题目链接 考虑两个\(\#\)之间产生的花费是怎样的.设这之间放了\(k\)个棋子,花费是\(\frac{k(k-1)}{2}\). 在\((r,c)\)处放棋子,行和列会同时产生花费,且花费和该行该 ...

随机推荐

  1. 20165314 2016-2017-2 《Java程序设计》第3周学习总结

    20165314 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 类体包含成员变量和域变量 局部变量只在方法内有效 对象的创建以及对象对自己变量和方法通过用. ...

  2. Chrome浏览器常用键盘快捷键介绍

    很多人喜欢使用键盘快捷键来操作电脑,因为在熟练的情况下,使用键盘会比使用鼠标点击更快.更高效.本文对Chrome浏览器常用的快捷键做个说明. 标签页和窗口快捷键 1.  Ctrl + n 打开新窗口 ...

  3. Java享元模式

    定义:提供了减少对象数量从而改善应用所需的对象结构的方式 运用共享技术有效支持大量细微度的对象 类型:结构型 应用场景:系统底层的开发啊,以便解决系统的性能问题 系统有大量的相似对象,需要缓存池的场景 ...

  4. python---hash查找

    以前只会用,没了解过原理. # coding = utf-8 class HashTable: def __init__(self): # 哈希表的初始大小已经被选择为 11.尽管这是任意的,但是重要 ...

  5. Processing3 1.随机行走

    class Walker { int x; int y; Walker() { x = width/2; y = height/2; } void display() { stroke(0); poi ...

  6. 【演示】在CSS里用calc进行计算

    请阅读 在CSS里用calc进行计算   下面的元素的width,padding,margin都使用了CSS calc进行计算. 简单计算: 100% – 100px 这是经过简单计算的元素宽度 复杂 ...

  7. 【转】ArcGIS10.0完全卸载全攻略

    ArcGIS10.0完全卸载详细步骤: 1.开始>控制面板>添加删除程序,卸载所有ArcGIS软件和帮助文档,以及所有ArcGIS补丁.2.从添加删除程序面板中删除所有Python相关的应 ...

  8. Js计算时间差,天数,小时数,余数

    var begintime_ms = Date.parse(new Date(begintime.replace(/-/g, "/"))); //begintime 为开始时间 v ...

  9. 通过impala更改Kudu表属性

    开发人员可以通过更改表的属性来更改 Impala 与给定 Kudu 表相关的元数据.这些属性包括表名, Kudu 主地址列表,以及表是否由 Impala (内部)或外部管理. Rename an Im ...

  10. bootstrap AdminLTE模版的使用

    参考:  https://adminlte.io/themes/AdminLTE/documentation/index.html  https://blog.csdn.net/gebitan505/ ...