题目描述

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

神的指示是一个字符串,记为字符串 \(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);
}

最新文章

  1. 使用 ApacheBench 进行轻量级压力测试
  2. 关于高性能Web服务的一点思考
  3. PE-1 &amp; 暴模|容斥
  4. MVC中使用HTML Helper类扩展HTML控件
  5. sass中mixin常用的CSS3
  6. 云计算服务模型,第 1 部分: 基础架构即服务(IaaS)
  7. python使用sqlite3
  8. [转]C# FileSystemWatcher监控指定文件或目录的文件的创建、删除、改动、重命名等活动
  9. CentOS6.5 Nginx优化编译配置[续]
  10. python3 验证用户名密码
  11. 远程连接(ssh安装)
  12. asp.net core mvc剖析:处理管道构建
  13. BLE空中升级 谈(二)
  14. java学习路线图-----java基础学习路线图(J2SE学习路线图)
  15. 【带着canvas去流浪(4)】绘制散点图
  16. codeforces 796A-D
  17. linux命令总结----转载
  18. 如何抓取电商的数据 &amp; Python
  19. winform 写入txt
  20. WIN10刚开机任务管理显示CPU占用100%问题

热门文章

  1. WARNING:Your password has expired --linux 用户密码过期
  2. MySQL执行计划值type,强烈推荐
  3. springboot添加servlet的两种方法
  4. kmeans 对表达量进行聚类
  5. [Oracle] Io Error: The Network Adapter could not establish the connection 解决方案
  6. Python--代码1(接口测试:测试用例从数据库读取写到yaml文件中)
  7. day30——socket套接字(完全版)
  8. Selenium 配置IE浏览器
  9. ArcGIS 字段计算器 Python 坑
  10. Intel realSense ubuntu 16.04+python 环境配置指南