原文链接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. Linux内存使用调整

    前段时间在做播放器的时候,遇到个问题,花了很长时间,做个记录,希望对有需要的人有所帮助: 播放器的播视频的时候,无论是手动切换视频还是到视频播放完成,自动切换视频,一定次数后均出现黑屏现象,偶尔有声音 ...

  2. Python 队列

    import multiprocessing import time if __name__ == '__main__': # 创建消息队列 # 3: 表示消息队列最大个数 queue = multi ...

  3. SwipeRefreshLayout详解和自定义上拉加载更多

    个人主页 演示Demo下载 本文重点介绍了SwipeRefreshLayout的使用和自定View继承SwipeRefreshLayout添加上拉加载更多的功能. 介绍之前,先来看一下SwipeRef ...

  4. VBS猜数游戏

    VBS 猜数游戏 2018-11-09  21:19:11 by xutao msgbox "The Swami" ,,"Game" msgbox " ...

  5. css3 自定义滚动条样式

    ::-webkit-scrollbar :滚动条整体部分 ::-webkit-scrollbar-thumb :滚动条里面的小方块样式 ::-webkit-scrollbar-track 滚动条的轨道 ...

  6. 学习promise

    总概括 promise是js异步编程的一种解决方案 我对promise的认识(通俗):给一个承诺promise,如果未来发生的事情(异步操作)是符合满足相应条件,则接受resolve,否则失败reje ...

  7. swift 实践- 11 -- UISlider

    import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoa ...

  8. JS和Jquery获取和修改label的值的示例代码

    abel标签在JS和Jquery中使用不能像其他标签一样用value获取它的值,下面有个不错的示例,希望大家可以学习下 来源:  <  JS和Jquery获取和修改label的值的示例代码  & ...

  9. oracle_基本SQL语言

      一:DDL数据定义语言 1:create(创建)       创建表 CREATE TABLE <table_name>( column1 DATATYPE [NOT NULL] [P ...

  10. 将Maven项目打包成可执行jar文件(引用第三方jar)

    方法一. mvn assembly 或 mvn package (一个jar包) 把依赖包和自己项目的文件打包如同一个jar包(这种方式对spring的项目不支持) <build>     ...