原文链接https://www.cnblogs.com/zhouzhendong/p/CF117G2.html

题目传送门 - CF177G2

题意

  定义斐波那契字符串如下:

  $s_1="a"$

  $s_2="b"$

  $s_i=s_{i-1}+s_{i-2}\ \ \ \ \ (i\geq 3)$

  给定 $k,m$,以及对应的 $m$ 组询问。

  每组询问一个字符串 $x$ ,问 $x$ 在 $s_k$ 中出现了多少次。

  $k\leq 10^{18},m\leq 10^4,|x|\leq 10^5$

题解

  看到 $k$ 如此大,首先要想到矩阵快速幂。

  但这个想法暂时还没什么用。

  让我们来观察一下字符串的性质。

  下面我们分别左对齐和右对齐来看一看斐波那契串。

$$\begin{eqnarray*}a\\b\\ba\\bab\\babba\\babbabab\\babbababbabba\\babbababbabbababbabab\end{eqnarray*}$$

$$\begin{align*}&a\\&b\\&ba\\&bab\\&babba\\&babbabab\\&babbababbabba\\&babbababbabbababbabab\end{align*}$$

  我们可以发现并证明以下性质:

  $1.$  对于任意 $i(i>1)$ ,$s_i$ 为 $s_{i+1}$ 的前缀。

  $2.$  对于任意 $i(i>0)$ ,$s_i$ 为 $s_{i+2}$ 的后缀。

  于是:当斐波那契串长度大于询问串的时候,拼接串时在拼接处产生的新的匹配数的变化周期为 $2$ 。

  于是,对于长度大于询问串的情况,直接搞两个转移矩阵然后快速幂一下就可以了。

  如果长度小于询问串,那么直接回答 $0$ 。

  现在再仔细的看看如何求拼接处产生的匹配数。

  我们记串 $x$ 在 $s$ 中的出现次数为 $KMP(s,x)$。

  则拼接 $s_i,s_{i+1}$ 时,拼接处产生的匹配数为 $KMP(s_{i+1}+s_{i},x)-KMP(s_i,x)-KMP(s_{i+1},x)$ 。

  转移矩阵的构造就不说了,比较基础的,请直接看代码。

  每次从头开始拼接产生第一个长度比当前询问串大的斐波那契串的复杂度会超时,所以我们需要离线按照询问串长度从小到大来。

  这样的复杂度为$O(\max{|x|}+m\log m+3^3\log k+\sum \max(|x|,|s_{f(|x|)}|))\approx O(m\log m+\sum{|x|})$。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+5,mod=1e9+7;
struct Mat{
static const int N=3;
int v[N][N];
Mat(){}
Mat(int x){
memset(v,0,sizeof v);
if (x==1)
for (int i=0;i<N;i++)
v[i][i]=1;
}
void set(int p){
v[0][0]=0,v[0][1]=1,v[0][2]=0;
v[1][0]=1,v[1][1]=1,v[1][2]=0;
v[2][0]=0,v[2][1]=p,v[2][2]=1;
}
void print(){
for (int i=0;i<3;i++,puts(""))
for (int j=0;j<3;j++)
printf("%3d ",v[i][j]);
puts("");
}
Mat operator * (Mat x){
Mat ans(0);
for (int i=0;i<N;i++)
for (int j=0;j<N;j++)
for (int k=0;k<N;k++)
ans.v[i][j]=(1LL*v[i][k]*x.v[k][j]+ans.v[i][j])%mod;
return ans;
}
Mat operator ^ (LL y){
Mat x=*this,ans(1);
while (y){
if (y&1LL)
ans=ans*x;
x=x*x,y>>=1;
}
return ans;
}
};
LL k;
int m;
struct STR{
string s;
int id,ans;
}s[N];
string s1="a",s2="b",s3="ba",s4="bab";
bool cmpL(STR a,STR b){
if (int(a.s.size())==int(b.s.size()))
return a.s<b.s;
return a.s.size()<b.s.size();
}
bool cmpid(STR a,STR b){
return a.id<b.id;
}
int Fail[N];
char S1[N],S2[N];
int KMP(string &s1,string &s2){
int n=s1.size(),m=s2.size();
for (int i=1;i<=n;i++)
S1[i]=s1[i-1];
for (int i=1;i<=m;i++)
S2[i]=s2[i-1];
Fail[0]=Fail[1]=0;
for (int i=2;i<=m;i++){
int k=Fail[i-1];
while (k&&S2[i]!=S2[k+1])
k=Fail[k];
if (S2[i]==S2[k+1])
k++;
Fail[i]=k;
}
int ans=0,k=0;
for (int i=1;i<=n;i++){
while (k&&S1[i]!=S2[k+1])
k=Fail[k];
if (S1[i]==S2[k+1])
k++;
if (k==m){
ans++;
k=Fail[k];
}
}
return ans;
}
int main(){
cin >> k >> m;
for (int i=1;i<=m;i++){
cin >> s[i].s;
s[i].id=i;
}
sort(s+1,s+m+1,cmpL);
int cnt=1;
for (int i=1;i<=m;i++){
while (cnt<k&&int(s1.size())<int(s[i].s.size())){
s1=s4+s3;
swap(s1,s2),swap(s2,s3),swap(s3,s4);
cnt++;
}
if (cnt==k){
s[i].ans=KMP(s1,s[i].s);
continue;
}
int a=KMP(s1,s[i].s),b=KMP(s2,s[i].s),c=KMP(s3,s[i].s),d=KMP(s4,s[i].s);
int del1=c-a-b,del2=d-b-c;
Mat st(0),tn1(0),tn2(0);
st.v[0][0]=a,st.v[0][1]=b,st.v[0][2]=1;
tn1.set(del1),tn2.set(del2);
st=st*((tn1*tn2)^((k-cnt)/2));
if ((k-cnt)&1)
st=st*tn1;
s[i].ans=st.v[0][0];
}
sort(s+1,s+m+1,cmpid);
for (int i=1;i<=m;i++)
printf("%d\n",s[i].ans);
return 0;
}

  

Codeforces 177G2 Fibonacci Strings KMP 矩阵的更多相关文章

  1. LightOJ 1268 Unlucky Strings (KMP+矩阵快速幂)

    题意:给出一个字符集和一个字符串和正整数n,问由给定字符集组成的所有长度为n的串中不以给定字符串为连续子串的有多少个? 析:n 实在是太大了,如果小的话,就可以用动态规划做了,所以只能用矩阵快速幂来做 ...

  2. codeforces 149E . Martian Strings kmp

    题目链接 给一个字符串s, n个字符串str. 令tmp为s中不重叠的两个连续子串合起来的结果, 顺序不能改变.问tmp能形成n个字符串中的几个. 初始将一个数组dp赋值为-1. 对str做kmp, ...

  3. [bzoj1009](HNOI2008)GT考试 (kmp+矩阵快速幂加速递推)

    Description 阿 申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学 A1A2...Am(0&l ...

  4. LightOJ 1268 Unlucky Strings(KMP+矩阵乘法+基础DP)

    题意 给出字符串的长度 \(n\) ,以及该字符串是由哪些小写字母组成,现给出一个坏串 \(S\) ,求存在多少种不同的字符串,使得其子串不含坏串. \(1 \leq n \leq 10^9\) \( ...

  5. codeforces gym #101161G - Binary Strings(矩阵快速幂,前缀斐波那契)

    题目链接: http://codeforces.com/gym/101161/attachments 题意: $T$组数据 每组数据包含$L,R,K$ 计算$\sum_{k|n}^{}F(n)$ 定义 ...

  6. HNOI2008 GT考试 (KMP + 矩阵乘法)

    传送门 这道题目的题意描述,通俗一点说就是这样:有一个长度为n的数字串(其中每一位都可以是0到9之间任意一个数字),给定一个长度为m的模式串,求有多少种情况,使得此模式串不为数字串的任意一个子串.结果 ...

  7. POJ 2406 Power Strings (KMP)

    Power Strings Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 29663Accepted: 12387 Descrip ...

  8. 【wikioi】1250 Fibonacci数列(矩阵乘法)

    http://wikioi.com/problem/1250/ 我就不说这题有多水了. 0 1 1 1 矩阵快速幂 #include <cstdio> #include <cstri ...

  9. poj 2406 Power Strings kmp算法

    点击打开链接 Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 27368   Accepted:  ...

随机推荐

  1. Sq lServer触发器的使用

    创建表: CREATE TABLE [dbo].[GeneralRule]( [ID] [int] NOT NULL, ) NULL, [DeleteFlag] [int] NOT NULL ) CR ...

  2. 【原创】大叔经验分享(39)spark cache unpersist级联操作

    问题:spark中如果有两个DataFrame(或者DataSet),DataFrameA依赖DataFrameB,并且两个DataFrame都进行了cache,将DataFrameB unpersi ...

  3. Shiro配置URL过滤

      常用过滤器: anon     不需要认证 authc     需要认证 user     验证通过或RememberMe登录的都可以   URL说明: /admin?=authc      表示 ...

  4. C语言-用函数实现社保工资查询系统

    需求: 1.有登陆操作,超过三次需重新打开登录 2.查询五险一金.税前税后工资计算,个人与单位应缴明细 3.输入税后工资和税前工资都可查询 4.退出有询问确认操作 代码如下; #include< ...

  5. MQ选型之RabbitMQ

    RabbitMQ是部署最广泛的开源消息代理.[官方原话] 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列(message queue),队列我们可以理解为管道.以管道的方式做消息传递. ...

  6. robot启动

    可以这句写入到bat文件里 pythonw.exe -c "from robotide import main; main()"

  7. JS跨域ajax访问

    方式1:jsonp解决跨域访问 需要服务和js配合 服务 [WebMethod] public void HelloWorld2(string name) { HttpContext.Current. ...

  8. Oracle12c Data Guard搭建手册

    Oracle12c Data Guard搭建手册 注:本文来源: 红黑联盟 < Oracle12c Data Guard搭建手册 > Oracle 12c 的DataGuard 是在CDB ...

  9. Confluence 6 连接到 Jira 用户管理的限制

    当你在使用 JIRA 目录为用户目录的时候,请考虑下面的一些限制和建议. 不知道跨平台的多应用单点登录 当你使用 JIRA 为你的目录管理器的时候,系统将不能支持跨平台的单点登录.当 JIRA 用作目 ...

  10. 用ngif 多次判断 Expression has changed after it was checked

    昨天遇到一个问题 ,用ng Expression has changed after it was checked 查了一下说在angular2中,这个错误只会在dev开发模式下出现,在pro发布版本 ...