原文链接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. pyhon 前面补充和set

    一, 主要内容. 补充一个字符串的基本操作 li = ["李嘉诚", "麻花藤", "黄海峰", "刘嘉玲"] s = ...

  2. Mysql 数据库增删改查

    数据插入 语法:INSERT INTO Table_name(field1,field2……fieldN) values(value1,vlaue2,…valueN) 单行插入用户类型 INSERT ...

  3. linux流量异常查看哪些程序占用的

    Linux下进程/程序网络带宽占用情况查看工具 -- NetHogs   http://www.vpser.net/manage/nethogs.html   来自.  最后略有修改 之前VPS侦探曾 ...

  4. C# Winform控件对透明图片重叠时导致图片不透明的解决方法(转)

    在Winform中如果将一个透明图片放在窗体上能正常显示透明,但是如果将该图片放在另一个控件上会导致不能显示透明效果. 解决这种情况,可以采取在控件上使用GDI+绘画出透明图片. 这里我们就以一个pi ...

  5. mybatis 按in 函数参数顺序排序

    使用 FIELD()函数 SELECT *  FROM   user  WHERE id IN (72, 80, 69)  ORDER BY FIELD(id, 72, 80, 69)

  6. Confluence 6 的小型文字档案(Cookies)

    这个页面列出了存储在 Confluence 用户浏览器中的小型文字档案(Cookies)内容.这些内容是由 Confluence 自己创建的.这个页面不会列出由 Confluence 安装的第三方插件 ...

  7. Confluence 6 配置 HTTP 超时设置

    当宏,例如 RSS Macro 进行 HTTP 请求的时候,有可能因为请求的时间比较长,而导致超时.你可以通过设置系统参数来避免这个问题. 配置 HTTP 超时设置: 在屏幕的右上角单击 控制台按钮  ...

  8. 自定义你的 Confluence 6 站点

    本部分对 Confluence 全站进行自定义的相关内容进行了说明.这部分只能是具有 Confluence 的管理员权限的用户才能进行操作 —— 系统管理员或者 Confluence 管理员. 有关对 ...

  9. npx简介(转载)

    npm v5.2.0引入的一条命令(npx),引入这个命令的目的是为了提升开发者使用包内提供的命令行工具的体验. 举例:使用create-react-app创建一个react项目. 老方法: npm ...

  10. linux 下安装vscode

    下载安装包 https://code.visualstudio.com/docs/?dv=linux64_deb (注意是deb包) sudo dpkg -i code_1.18.1-15108573 ...