题目描述

一天小甲苯得到了一条神的指示,他要把神的指示写下来,但是又不能泄露天机,所以他要用一种方法把神的指示记下来。

神的指示是一个字符串,记为字符串 \(s_1\),\(s_1\) 仅包含小写字母 \(\texttt{a-z}\)。

现在小甲苯想要写下神的指示,记为字符串 \(s_2\),\(s_2\) 仅包含小写字母 \(\texttt{a-z}\),要求 \(s_1\) 中的相邻的两个字母不能在 \(s_2\) 中相邻地出现。

现在给定 \(s_2\) 的长度,小甲苯想知道他有多少种方法可以将神的指示写下来。

输出种类数对 \(10^9 + 7\) 取模的结果。

输入格式

文件的第一行只有一个正整数 \(n\),代表字符串 \(s_2\) 的长度,\(n \le 10^{15}\)。

第二行是一个字符串,代表字符串 \(s_1\)。\(s_1\) 的长度不超过 \(100000\)。

输出格式

输出一个整数,表示小甲苯可以写出的字符串的总数。

结果对 \(10^9 + 7\) 取模。

样例

样例输入

2
ab

样例输出

675

数据范围与提示

对于 \(30\%\) 的数据,\(n ≤ 100000\);

对于 \(100\%\) 的数据,\(n ≤ 10^{15}\)。

题解

我的做法其实应该和网上的题解差不多。不过理解起来可能需要比较感性一点?

因为考虑的只有相邻两个字符,不难得知,可以把所有关系写成一个\(26\times 26\)的矩阵。

先思考一下正常怎么求解:\(f[i][j]=\sum f[i-1][k]*a[k][j]\) (\(i\)位第几位数字,\(j\)为当前放的字母,\(k\)为上一位放的字母)

那么我们把\(f[i]\)视为一个\(1\times n\)的矩阵,实际上这就是一个矩阵乘法的过程。

利用矩阵快速幂求解即可。

但是我构造的初始的矩阵有点不同:初始矩阵为一个全\(1\)的矩阵,最后统计答案时答案为\(\sum f[i][i]\)

怎么理解呢?实际上就是第一位怎么放都行,然后矩阵乘法得到的矩阵中的\(c[i][j]\),实际上就是第一个矩阵的第\(i\)行与第二个矩阵的第\(j\)列的答案。所以最终的\(f[i][i]\)即为第一位填\(i\)可以得到的方案数。

那么为什么要这么构造就不难理解了。

#include <bits/stdc++.h>
using namespace std; #define ll long long
const int N = 100010;
const ll mod = 1e9 + 7; ll n;
char s[N];
struct mat {
ll m[26][26];
}; mat operator * (mat a, mat b) {
mat c;
memset(c.m, 0, sizeof(c.m));
for(int i = 0; i < 26; ++i) {
for(int j = 0; j < 26; ++j) {
for(int k = 0; k < 26; ++k) {
c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod;
}
}
}
return c;
} mat base, ans, now; int idx(char c) {return c - 'a';} void print(mat a) {
for(int i = 0; i < 26; ++i) {
for(int j = 0; j < 26; ++j) printf("%d ", a.m[i][j]);
puts("");
}
} int main() {
scanf("%lld%s", &n, s + 1);
for(int i = 0; i < 26; ++i) for(int j = 0; j < 26; ++j) base.m[i][j] = 1;
int len = strlen(s + 1);
for(int i = 1; i < len; ++i) {
base.m[idx(s[i])][idx(s[i + 1])] = 0;
} memset(ans.m, 0, sizeof(ans.m));
memset(now.m, 0, sizeof(now.m));
for(int i = 0; i < 26; ++i) ans.m[i][i] = 1; --n;
while(n) {
if(n & 1) ans = ans * base;
base = base * base; n >>= 1;
}
for(int i = 0; i < 26; ++i) for(int j = 0; j < 26; ++j) now.m[i][j] = 1;
now = now * ans; ll sum = 0;
for(int i = 0; i < 26; ++i) sum = (sum + now.m[i][i]) % mod;
printf("%lld\n", sum);
}

LOJ#3104「TJOI2019」甲苯先生的字符串的更多相关文章

  1. LG5337/BZOJ5508 「TJOI2019」甲苯先生的字符串 线性动态规划+矩阵加速

    问题描述 LG5337 BZOJ5508 题解 设\(opt_{i,j}(i \in [1,n],j \in [1,26])\)代表区间\([1,i]\),结尾为\(j\)的写法. 设\(exist_ ...

  2. 【LOJ】#3109. 「TJOI2019」甲苯先生的线段树

    LOJ#3109. 「TJOI2019」甲苯先生的线段树 发现如果枚举路径两边的长度的话,如果根节点的值是$x$,左边走了$l$,右边走了$r$ 肯定答案会是$(2^{l + 1} + 2^{r + ...

  3. LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

  4. LG5338/BZOJ5509/LOJ3105 「TJOI2019」甲苯先生的滚榜 Treap

    问题描述 LG5338 LOJ3105 BZOJ5509 题解 建立一棵\(\mathrm{Treap}\),把原来的\(val\)换成两个值\(ac,tim\) 原来的比较\(val_a<va ...

  5. 「TJOI2019」甲苯先生的滚榜

    题目链接 问题分析 参照数据范围,我们需要一个能够在\(O(n\log n)\)复杂度内维护有序数列的数据结构.那么平衡树是很好的选择.参考程序中使用带旋Treap. 参考程序 #pragma GCC ...

  6. @loj - 2106@ 「JLOI2015」有意义的字符串

    目录 @description@ @solution@ @accepted code@ @details@ @description@ B 君有两个好朋友,他们叫宁宁和冉冉.有一天,冉冉遇到了一个有趣 ...

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

随机推荐

  1. PDF阅读器关闭“使用手型工具阅读文章”功能

    1.问题描述 某些PDF文件打开时,光标显示的手型工具里面有个箭头,一点击鼠标左键,就跳转到下一页了.给阅读带来很多不便. 2.原因 因为这类PDF文档中带有"文章"(articl ...

  2. (CSDN迁移) 替换字符串中的空格

    题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. public ...

  3. [05]Go设计模式:建造者模式(Builder Pattern)

    目录 建造者模式 一.简介 二.代码 三:参考资料 建造者模式 一.简介 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式, ...

  4. 下一代无服务器的发展形态: Serverless2.0

    6 月 25 日,在上海召开的 KubeCon 2019 大会上,腾讯云重磅发布了下一代无服务器的发展形态:Serverless2.0.本文将以 Serverless 的概念.发展.形态.应用以及技术 ...

  5. Django的Xadmin使用

    Django Xadmin 通常在实际的开发当中, 除了前后端分离的项目, 还有一些前后端不分离的项目, 这样我们在访问不分离的页面的时候, 就可以通过Django自带的admin管理模块来轻松实现后 ...

  6. proxy_banner

  7. 访问Harbor报502 Bad Gateway

    Harbor启动都是多个容器的,首先查看一下是否有相关容器未启动 docker ps | grep harbor cae340214e57 goharbor/nginx-photon:v1.9.3 & ...

  8. 如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全

    原文:如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全 .NET 中提供了一些线程安全的类型,如 ConcurrentDictionary<TKey, TVa ...

  9. c# Path.Combine

    Path.Combine: c#获取当前项目路径 : //获取包含当前执行的代码的程序集的加载文件的完整路径 var appPath = System.IO.Path.GetDirectoryName ...

  10. MySQL连接使用

    在mysql查询中,我们会通过排序,分组等在一张表中读取数据,这是比较简单的,但是在真正的应用中经常需要从多个数据表中读取数据.下面就为大家介绍这种方式,链接查询join. INNER JOIN(内连 ...