Codeforces 177G2 Fibonacci Strings KMP 矩阵
原文链接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 矩阵的更多相关文章
- LightOJ 1268 Unlucky Strings (KMP+矩阵快速幂)
题意:给出一个字符集和一个字符串和正整数n,问由给定字符集组成的所有长度为n的串中不以给定字符串为连续子串的有多少个? 析:n 实在是太大了,如果小的话,就可以用动态规划做了,所以只能用矩阵快速幂来做 ...
- codeforces 149E . Martian Strings kmp
题目链接 给一个字符串s, n个字符串str. 令tmp为s中不重叠的两个连续子串合起来的结果, 顺序不能改变.问tmp能形成n个字符串中的几个. 初始将一个数组dp赋值为-1. 对str做kmp, ...
- [bzoj1009](HNOI2008)GT考试 (kmp+矩阵快速幂加速递推)
Description 阿 申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学 A1A2...Am(0&l ...
- LightOJ 1268 Unlucky Strings(KMP+矩阵乘法+基础DP)
题意 给出字符串的长度 \(n\) ,以及该字符串是由哪些小写字母组成,现给出一个坏串 \(S\) ,求存在多少种不同的字符串,使得其子串不含坏串. \(1 \leq n \leq 10^9\) \( ...
- codeforces gym #101161G - Binary Strings(矩阵快速幂,前缀斐波那契)
题目链接: http://codeforces.com/gym/101161/attachments 题意: $T$组数据 每组数据包含$L,R,K$ 计算$\sum_{k|n}^{}F(n)$ 定义 ...
- HNOI2008 GT考试 (KMP + 矩阵乘法)
传送门 这道题目的题意描述,通俗一点说就是这样:有一个长度为n的数字串(其中每一位都可以是0到9之间任意一个数字),给定一个长度为m的模式串,求有多少种情况,使得此模式串不为数字串的任意一个子串.结果 ...
- POJ 2406 Power Strings (KMP)
Power Strings Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 29663Accepted: 12387 Descrip ...
- 【wikioi】1250 Fibonacci数列(矩阵乘法)
http://wikioi.com/problem/1250/ 我就不说这题有多水了. 0 1 1 1 矩阵快速幂 #include <cstdio> #include <cstri ...
- poj 2406 Power Strings kmp算法
点击打开链接 Power Strings Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 27368 Accepted: ...
随机推荐
- mysqlfrm初步使用
这个工具也就是读取frm文件生成建表语句默认的模式是再生个实例,使用--basedir选项或指定--server选项来连接到已经安装的实例.这种过程不会改变原始的.frm文件.该模式也需要指定--po ...
- ASP.NET MVC5高级编程 之 模型
1. 为MVC Music Store建模 Models文件夹(右击) --> 添加 --> 类 为类添加对应的属性: public class Album { public virtua ...
- CF 313B
题意: 给你一个字符串, 然后m次区间查询,求出区间有多少组 str[i] == str[i+1] 就是一个水DP了 有则Dp[i] = Dp[i-1] 无则 Dp[i] = Dp[i-1]: (刚开 ...
- LA 3263 (欧拉定理)
欧拉定理题意: 给你N 个点,按顺序一笔画完连成一个多边形 求这个平面被分为多少个区间 欧拉定理 : 平面上边为 n ,点为 c 则 区间为 n + 2 - c: 思路: 先扫,两两线段的交点,存下来 ...
- hadoop生态系统主要架构图汇总
1 hadoop1.0时期架构 2 hadoop2.0时期架构 3 hdfs架构 [Active Namenode]:主 Master(只有一个),管理 HDFS 的名称空间,管理数据块映射信息:配置 ...
- Laravel 怎么使用资源控制器delete方法
### 在视图上,想删除某个数据,而控制器是使用了resources controller的 那么在删除数据的时候,还是有些需要注意的地方 ### 视图上: <a href="java ...
- scp命令:远程复制粘贴文件
文章链接:https://www.cnblogs.com/webnote/p/5877920.html scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有 ...
- swift 实践- 05 -- UITextField
import UIKit class ViewController: UIViewController ,UITextFieldDelegate{ // 文本框的创建, 有如下几个样式: // UIT ...
- Confluence 6 找到在创建 XML 备份的时候出现的错误
错误可能是因为数据库突然不可访问而产生.如果你在你的日志中看到了错误 'Couldn't backup database data' ,这个指南将会帮助你更正这个错误.我们强烈推荐你备份 Confl ...
- nginx代理跨域(mac)
首先找到nginx.conf文件,修改并添加如下配置 html 文件 <!DOCTYPE html> <html lang="en"> <head&g ...