题意:定义斐波那契字符串为:

  • $f_1 = $ "a"
  • \(f_2 =\) "b"
  • \(f_n = f_{n-1} + f_{n-2}, \, n > 2\)

例如,$f_3 = $ “ba”。

有\(m\)次询问,第\(i\)次给出一个字符串\(s_i\),问\(s_i\)在\(f_n\)中的出现次数。

\(m \leq 10^4, \, n \leq 10^{18}, \, \sum|s_i| \leq 10^5\)

主要问题在与\(f_p\)与\(f_{p-1}\)拼接时,\(f_p\)的某个后缀与\(f_{p-1}\)的某个前缀可能恰好拼成\(s_i\),即产生额外的出现次数。当\(|f_p|\)与\(|f_{p-1}|\)都大于等于\(|s_i|\)时,这个数值就等于\(f_{n}\)长度为\(|s_i|-1\)的后缀与\(f_{p-1}\)长度为\(|s_i|-1\)的前缀组成的字符串中\(s_i\)的出现次数。

我们设\(f_{p-1}\)长度为\(|s_i|-1\)的前缀为\(a\),长度为\(|s_i|-1\)的后缀为\(b\),\(f_{p}\)长度为\(|s_i|-1\)的前缀为\(a\),长度为\(|s_i|-1\)的后缀为\(c\)。我们观察发现:

| | 长度为\(|s_i|-1\)的前缀 | 长度为\(|s_i|-1\)的后缀 | 产生额外贡献的字符串 |

| ------------ | --------------------- | --------------------- | -------------------- |

| \(f_{p-1}\) | \(a\) | \(b\) | |

| \(f_p\) | \(a\) | \(c\) | \(ca\) |

| \(f_{p+1}\) | \(a\) | \(b\) | \(ba\) |

| \(f_{p+2}\) | \(a\) | \(c\) | \(ca\) |

| \(f_{p+3}\) | \(a\) | \(b\) | \(ba\) |

| …… | …… | …… | …… |

| \(f_{p+2k}\) | \(a\) | \(c\) | \(ca\) |

| \(f_{p+2k+1}\) | \(a\) | \(b\) | \(ba\) |

我们设\(s_i\)在\(ca\)中的出现次数为\(n_c\),在\(ba\)中的出现次数为\(n_b\),\(O_n\)表示\(s_i\)在\(f_{n+p}\)中的出现次数。

那么,容易得到

\[O_n = O_{n-1} + O_{n-2} + \begin{cases} n_c, & \text {if $ n\mod 2 = 0$} \\ n_b, & \text{if $n \mod 2 = 1$}\end{cases}
\]

考虑拆分贡献,即设\(A_n\),\(B_n\),\(C_n\)分别表示\(f_n\)中,\(s_i\)在\(f_p\)和\(f_{p+1}\)中的出现次数,在所有\(ba\)中的出现次数,在所有\(ca\)中的出现次数。那么,我们有

  • \(O_n = A_n + B_n \times n_b + C_n \times n_c\)
  • \(A_n = A_{n-1} + A_{n-2}\)
  • \(B_n = B_{n-1} + B_{n-2} + [n \mod 2 = 1] = B_{n-1} + B_{n-2} + \frac {1 - (-1)^n} {2}\)
  • \(C_n = C_{n-1} + C_{n-2} + [n \mod 2 = 0] = C_{n-1} + C_{n-2} + \frac {1 + (-1)^n} {2}\)
  • \(B_0 = B_1 = C_0 = C_1 = 0\)

其中,\(A_n\)在我们计算出\(A_0\)和\(A_1\)后,用矩阵快速幂得到。故我们只用考虑\(B_n\)和\(C_n\)这两个类似的数列。

通过使用OEIS或其他的数列求解方法,我们得到\(B_n = F_{n-1} - \frac {1+(-1)^n}{2}\),以及\(C_n = F_{n} - \frac{1 - (-1)^n}{2}\)。其中,\(F_n\)为第\(n\)个斐波那契数。它们同样可以用矩阵快速幂求出。

时间复杂度\(O(\sum|s_i| + m \log n )\)。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 30010, MAX = 200000, MOD = 1000000007;
string fib[N];
int n,m,len,cnt,lef[N],nex[MAX + 10];
char tmp[MAX + 10];
string a,b,c,tp;
struct matrix {
int mat[3][3];
matrix() {
memset(mat,0,sizeof mat);
}
matrix operator * (const matrix& x) const {
matrix ret = matrix();
for (int k = 1 ; k <= 2 ; ++ k)
for (int i = 1 ; i <= 2 ; ++ i)
for (int j = 1 ; j <= 2 ; ++ j)
(ret.mat[i][j] += 1ll * mat[i][k] * x.mat[k][j] % MOD) %= MOD;
return ret;
}
};
matrix bas;
matrix power(matrix a,int b) {
matrix ret = matrix();
ret.mat[1][1] = ret.mat[2][2] = 1;
while (b) {
if (b&1) ret = ret * a;
a = a * a;
b >>= 1;
}
return ret;
}
int getfib(int x) {
matrix ret = power(bas,x);
return ret.mat[1][2];
}
int getnum() {
int ret = 0;
for (int i = 0, j = 0 ; i < (int)tp.length() ; ++ i) {
while (j >= 0 && tmp[j+1] != tp[i])
j = nex[j];
++ j;
if (j == len) ++ ret, j = nex[j];
}
return ret;
}
int solve() {
nex[0] = -1;
for (int i = 2, j = 0 ; i <= len ; ++ i) {
while (j >= 0 && tmp[j+1] != tmp[i])
j = nex[j];
nex[i] = ++j;
}
int p = lower_bound(lef+1,lef+cnt+1,len) - lef;
++ p;
if (n <= p+1) {
tp = fib[n];
return getnum();
}
a = fib[p].substr(0,len-1);
b = fib[p].substr(lef[p] - len+1,len-1);
c = fib[p+1].substr(lef[p+1] - len+1,len-1);
int nb, nc, n0, n1, pos = n - p, ret = 0;
tp = b + a;
nb = getnum();
tp = c + a;
nc = getnum();
tp = fib[p];
n0 = getnum();
tp = fib[p+1];
n1 = getnum();
(ret += 1ll * (getfib(pos) - (pos&1)) * nc % MOD) %= MOD;
(ret += 1ll * (getfib(pos-1) - 1 + (pos&1)) * nb % MOD) %= MOD;
matrix sta = matrix();
sta.mat[1][1] = n1;
sta.mat[1][2] = sta.mat[2][1] = n0;
sta = sta * power(bas,pos);
(ret += sta.mat[1][2]) %= MOD;
ret = (ret % MOD + MOD) % MOD;
return ret;
}
signed main() {
fib[1] = "a";
fib[2] = "b";
for (int i = 3 ; ; ++ i) {
fib[i] = fib[i-1] + fib[i-2];
lef[i] = fib[i].length();
cnt = i;
if (lef[i-1] >= MAX) break;
}
bas.mat[1][1] = bas.mat[1][2] = bas.mat[2][1] = 1;
cin >> n >> m;
for (int i = 1 ; i <= m ; ++ i) {
scanf("%s",tmp+1);
len = strlen(tmp+1);
cout << solve() << endl;
}
return 0;
}

小结:用一种不大简单的做法做出了这道题。思考时间过长,并且依赖网站来求解数列,这是做此题时体现出的不足之处。

【做题】CF177G2. Fibonacci Strings——思维+数列的更多相关文章

  1. 【做题】NOWCODER142A Ternary String——数列&欧拉定理

    题意:你有一个长度为\(n\),且仅由012构成的字符串.每经过一秒,这个字符串所有1后面会插入一个0,所有2后面会插入一个1,然后会删除第一个元素.求这个字符串需要多少秒变为空串,对\(10^9+7 ...

  2. noip做题记录+挑战一句话题解?

    因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...

  3. CodeM美团点评编程大赛复赛 做题感悟&题解

    [T1] [简要题意]   长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...

  4. (luogu1704)寻找最优美做题曲线 [TPLY]

    寻找最优美做题曲线 题目链接:https://www.luogu.org/problemnew/show/P1704 题目大意: 求包含指定点的最长不降子序列(严格递增) 题解 首先我们发现 一个序列 ...

  5. AtCoder Grand Contest 1~10 做题小记

    原文链接https://www.cnblogs.com/zhouzhendong/p/AtCoder-Grand-Contest-from-1-to-10.html 考虑到博客内容较多,编辑不方便的情 ...

  6. 课后选做题-MyOD

    课后选做题-MyOD od命令的了解 功能 od命令用于将指定文件内容以八进制.十进制.十六进制.浮点格式或ASCII编码字符方式显示,通常用于显示或查看文件中不能直接显示在终端的字符.od命令系统默 ...

  7. BJOI做题记录

    BJOI做题记录 终于想起还要做一下历年省选题了2333 然而咕了的还是比做了的多2333 LOJ #2178. 「BJOI2017」机动训练 咕了. LOJ #2179. 「BJOI2017」树的难 ...

  8. 【做题记录】AtCoder AGC做题记录

    做一下AtCoder的AGC锻炼一下思维吧 目前已做题数: 75 总共题数: 239 每一场比赛后面的字母是做完的题,括号里是写完题解的题 AGC001: ABCDEF (DEF) AGC002: A ...

  9. FJOI2017前做题记录

    FJOI2017前做题记录 2017-04-15 [ZJOI2017] 树状数组 问题转化后,变成区间随机将一个数异或一,询问两个位置的值相等的概率.(注意特判询问有一个区间的左端点为1的情况,因为题 ...

随机推荐

  1. UVa-1025城市里的间谍 A Spy in the Metro

    原题 城市里的间谍 分析 动态规划,dp[i][j]表示你在时刻i,车站j,最少还要等待的时间. 边界条件d[T][n]=0 已经到达,其他d[T][i]=inf不可达. 在一个站点时,有以下三种决策 ...

  2. sv命令空间 packge

    SV中的module,interface,program,checker,都提供declaration空间,内部定义都local当前的那个scope,相互之间的building block不影响,不识 ...

  3. C语言---变量与函数

    一个C程序是由一个或多个程序模块组成的,每一个程序模块作为一个源程序文件,一个源程序文件是一个编译单元. 源程序文件分为库函数和用户自己定义的函数,以及有参函数.无参函数. 函数调用的过程: 1) 定 ...

  4. <script> 属性crossorigin

    今日偶然见到如下代码: <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper. ...

  5. Rpgmakermv(38)MOG_Theatrhythm

    1.============================葡萄牙语=================================================+++ MOG - Theatrh ...

  6. 【Hadoop UI学习】Hue

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 zookeeper-3.4.11 Hue是一个开源的Apac ...

  7. 怎么查 ODBC Driver for SQL Server

    1)进入服务器,找到SQL Server 2016 Configuration... ,点进去就好了 2)

  8. python 读写json数据

    json 模块提供了一种很简单的方式来编码和解码JSON 数据. 字符串操作 其中两个主要的函数是json.dumps() 和json.loads() ,要比其他序列化函数库如pickle 的接口少得 ...

  9. Shell for while 循环

    li@ubuntu:~/test$ cat a.sh #!/bin/bash for loop in 1 2 3 4 5 do echo "The value is : $loop" ...

  10. Shell变量相关

    li@ubuntu:~/test$ vi test.sh li@ubuntu:~/test$ cat test.sh #!/bin/bash #shell变量不加引号;加单引号;加双引号都行 url= ...