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: ...
随机推荐
- pointer & iterator
pointer: address, use operator(*) to get/set the value 1) support operator(+,-), move to next posito ...
- 前端 ----jQuery的属性操作
04-jQuery的属性操作 jquery的属性操作模块分为四个部分:html属性操作,dom属性操作,类样式操作和值操作 html属性操作:是对html文档中的属性进行读取,设置和移除操作.比如 ...
- Go 常见严格格式汇总(struct,func...)不定期更新!
1 引言 Golang对格式有着较为严格的规定,例如方法大括号一定要放在方法名后,否则编译不过:变量(常量除外)未使用,也编译不过等等 2 例子 2.1 struct type person stru ...
- linux进程内存布局
一个程序本质上都是由 BSS 段.data段.text段三个组成的.这样的概念在当前的计算机程序设计中是很重要的一个基本概念,而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分 ...
- PHP项目笔记
1.controller输出前端传来的值:var_dump($_POST['oid']); 2.var_dump($_POST['oid']);die:
- Confluence 6 自定义 Decorator 模板的宏和针对高级用户
宏 页面的某些部分使用的是 Velocity 宏进行创建的,包括导航栏.有关宏的创建,你可以参考页面 Working With Decorator Macros 页面中的内容. 针对高级用户 vel ...
- 判断ie浏览器7、8、9三个版本
判断ie浏览器7.8.9三个版本 上午的时候,本来是想做一个position:fixed在各个浏览器下兼容的方案的,但是发现ie7/8下面的position:fixed只支持一个屏幕,如果内容高度 ...
- day05流程控制while循环 流程控制for循环
1.什么是循环:循环就是重复做某事 2.为何要有循环:为了计算机能够具备人重复做某事的能力 3,.如何用循环: 1.结束while循环的两种方法:1.修改条件:等到下一次循环开始时判断,条件为假才会结 ...
- django之数据库表的单表查询
一.添加表记录 对于单表有两种方式 # 添加数据的两种方式 # 方式一:实例化对象就是一条表记录 Frank_obj = models.Student(name ="海东",cou ...
- trade war
问题 C: trade war 时间限制: 1 Sec 内存限制: 128 MB 题目描述 2018年的春天,特朗普这个不靠谱的的家伙悍然向中国发起了贸易战,贸易战是一场没有赢家的战争,美国向中国商 ...