原文链接 https://www.cnblogs.com/cly-none/p/SRM701Div1C.html

题意:定义"Fibonacci string"为没有连续1的01串。现在,给出\(a,b\),定义一个"Fibonacci string"的权值为\(x^a y^b\),其中\(x\)为0的个数,\(y\)为1的个数。

要求对所有长度为\(n\)的"Fibonacci string"的权值求和,对\(10^9 + 7\)取模。

\(n \leq 10^9, \ a, b \leq 25\)

显然第一反应就是矩阵存下所有\((a,b)\)做快速幂。然而,这样的话矩阵的边长是\(O(a^2)\)的,不能通过本题。

考虑最终答案的式子:

\[\sum_{k=0}^n {n-k+1 \choose k} k^b (n-k)^a
\]

我们尝试化简:

\[\begin{aligned}
& \sum_{k=0}^n {n-k+1 \choose k} k^b (n-k)^a \\
= & \sum_{k=0}^n \sum_{j=0}^a {n-k+1 \choose k} k^b {a\choose j} n^{a-j} (-k)^j \\
= & \sum_{j=0}^a {a \choose j} (-1)^j \sum_{k=0}^n {n-k+1 \choose k}k^{b+j}
\end{aligned}
\]

注意到后面的\(\sum_{k=0}^n {n-k+1 \choose k} k^{b+j}\)就是当\(a' = 0, \ b' = b+j\)时,所有长度为\(n\)的"Fibonacci string"的权值和。这时,我们再建矩阵,边长就只有\(O(a)\)了。最后\(O(a)\)枚举\(j\)就能计算出答案。

时间复杂度\(O(a^3 \log n)\)。

#include <bits/stdc++.h>
using namespace std; const int MOD = (int)(1e9 + 7), N = 110;
struct matrix {
int n,m,mat[N][N];
matrix(int n=0,int m=0): n(n), m(m) {
memset(mat,0,sizeof mat);
}
matrix operator * (const matrix& a) const {
assert(m == a.n);
matrix ret = matrix(n, a.m);
for (int k = 0 ; k < m ; ++ k)
for (int i = 0 ; i < n ; ++ i)
for (int j = 0 ; j < a.m ; ++ j)
(ret.mat[i][j] += 1ll * mat[i][k] * a.mat[k][j] % MOD) %= MOD;
return ret;
}
};
matrix power(matrix a,int b) {
assert(a.n == a.m);
matrix ret = matrix(a.n, a.m);
for (int k = 0 ; k < a.n ; ++ k)
ret.mat[k][k] = 1;
while (b) {
if (b&1) ret = ret * a;
a = a * a;
b >>= 1;
}
return ret;
}
int power(int a,int b) {
int ret = 1;
while (b) {
if (b&1) ret = 1ll * ret * a % MOD;
a = 1ll * a * a % MOD;
b >>= 1;
}
return ret;
}
class FibonacciStringSum {
public:
int get( int n, int a, int b ) ;
};
int val[N],cmb[N][N];
int FibonacciStringSum::get(int n, int a, int b) {
memset(cmb,0,sizeof cmb);
for (int i = 0 ; i <= a + b ; ++ i)
cmb[i][0] = 1;
for (int i = 1 ; i <= a + b ; ++ i)
for (int j = 1 ; j <= i ; ++ j)
cmb[i][j] = (cmb[i-1][j] + cmb[i-1][j-1]) % MOD;
matrix sta = matrix(1, 2 * (a + b + 1));
matrix tran = matrix(2 * (a + b + 1), 2 * (a + b + 1));
sta.mat[0][0] = 1;
for (int i = 0 ; i <= a + b ; ++ i) {
tran.mat[i][i] = 1;
tran.mat[i + a + b + 1][i] = 1;
for (int j = 0 ; j <= i ; ++ j)
tran.mat[j][a + b + 1 + i] += cmb[i][j];
}
tran = power(tran, n);
sta = sta * tran;
for (int i = 0 ; i <= a + b ; ++ i)
val[i] = (sta.mat[0][i] + sta.mat[0][i + a + b + 1]) % MOD;
int ans = 0;
for (int i = 0, t = 1 ; i <= a ; ++ i, t = -t)
(ans += 1ll * t * cmb[a][i] * power(n, a - i) % MOD * val[b + i] % MOD) %= MOD;
ans = (ans % MOD + MOD) % MOD;
return ans;
}

小结:这个问题的特殊之处在于,既可以直接矩阵快速幂,也可以写成数学和式。然而,二者都不能直接解决这个问题。把两种方法相结合一直是常用的技巧(如分块),在这里也启示我们对于一个问题不能死板地但从一个方向来思考。

【做题】SRM701 Div1 Hard - FibonacciStringSum——数学和式&矩阵快速幂的更多相关文章

  1. [ An Ac a Day ^_^ ] hdu 4565 数学推导+矩阵快速幂

    从今天开始就有各站网络赛了 今天是ccpc全国赛的网络赛 希望一切顺利 可以去一次吉大 希望还能去一次大连 题意: 很明确是让你求Sn=[a+sqrt(b)^n]%m 思路: 一开始以为是水题 暴力了 ...

  2. 2018.09.26 bzoj5221: [Lydsy2017省队十连测]偏题(数学推导+矩阵快速幂)

    传送门 由于没有考虑n<=1的情况T了很久啊. 这题很有意思啊. 考试的时候根本不会,骗了30分走人. 实际上变一个形就可以了. 推导过程有点繁杂. 直接粘题解上的请谅解. 不得不说这个推导很妙 ...

  3. BZOJ 2326: [HNOI2011]数学作业( 矩阵快速幂 )

    BZOJ先剧透了是矩阵乘法...这道题显然可以f(x) = f(x-1)*10t+x ,其中t表示x有多少位. 这个递推式可以变成这样的矩阵...(不会用公式编辑器...), 我们把位数相同的一起处理 ...

  4. [HNOI2011]数学作业 矩阵快速幂 BZOJ 2326

    题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 NNN 和 MMM ,要求计算Concatenate(1..N) Concatenate (1 .. N) ...

  5. 51nod 1242 斐波那契数列的第N项——数学、矩阵快速幂

    普通算法肯定T了,所以怎么算呢?和矩阵有啥关系呢? 打数学符号太费时,就手写了: 所以求Fib(n)就是求矩阵  |  1  1  |n-1  第一行第一列的元素. |  1  0  | 其实学过线代 ...

  6. Codeforces Round #362(Div1) D Legen...(AC自动机+矩阵快速幂)

    题目大意: 给定一些开心串,每个串有一个开心值,构造一个串,每包含一次开心串就会获得一个开心值,求最大获得多少开心值. 题解: 首先先建立AC自动机.(建立fail指针的时候,对val要进行累加) 然 ...

  7. 刷题总结—— Scout YYF I(poj3744 矩阵快速幂+概率dp)

    题目: Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate int ...

  8. hdu 5171 GTY's birthday gift(数学,矩阵快速幂)

    题意: 开始时集合中有n个数. 现在要进行k次操作. 每次操作:从集合中挑最大的两个数a,b进行相加,得到的数添加进集合中. 以此反复k次. 问最后集合中所有数的和是多少. (2≤n≤100000,1 ...

  9. (中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。

    In the country there are exactly n cities numbered with positive integers from 1 to n. In each city ...

随机推荐

  1. Python 3+selenium+unittest+HTMLTestRunner生成测试报告

    一.下载HTMLTestRunner.py,解压,将它放到 python安装路径的site-packages目录下 https://pan.baidu.com/s/1epWlibxbxWlNoIcxL ...

  2. Linux常用命令之-删除文件

    在测试过程中,有时候会需要删除一些文件,例如日志文件过大等,这里汇总一些删除文件常用的命 已这个系统内的文件为例 删除文件(即这个文件被删除) 单个删除:rm -f + 文件名 eg:rm -f  2 ...

  3. Java集合List、Set、Map

    集合是 java 基础中非常重要的一部分,同样也是 Java 面试中很重要的一个知识点.所以,给王小整理了这篇关于集合的文章. 1.接口继承关系以及实现 集合类存放于 Java.util 包中,主要有 ...

  4. python类与对象-如何创建可管理的对象属性

    如何创建可管理的对象属性 问题举例 在面向对象编程中, 我们把方法看作对象的接口, 直接访问对象的属性可能是不安全的,或设计上不够灵活. 但是使用调用方法在形式上不如访问属性简洁. circle.ge ...

  5. cocos2d-x C++ 获取网络图片缓存并展示

    #ifndef __HttpGetImg__ #define __HttpGetImg__ #include "cocos2d.h" #include "HttpRequ ...

  6. libpng warning: iCCP: known incorrect sRGB profile

    参考  http://www.cocos2d-x.org/forums/6/topics/49093 解决 I got the following warnings in console when r ...

  7. python实现可以被with上下文管理的类或函数

      # .开始之前先明确一下with机制 # 1.类包函数__enter__()和__exit__()函数,即是可以被上下文管理的类 # __enter__用来执行with时的方法,__exit__返 ...

  8. 实现一个自定义的ArrayList类,实现将原List中的每个数据都乘以10

    1.首先自定义一个Operate接口,如下所示: public interface Operate { public Integer caozuo(Integer i); } 2.实现自定义的Arra ...

  9. 2018-2019-2 网络对抗技术 20165305 Exp6 信息搜集与漏洞扫描

    1.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 2.实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具 ...

  10. 安装pip、numpy、sklearn

    1)pip安装:https://pip.pypa.io/en/stable/installing/To install pip, securely download get-pip.py. [1]:c ...