#incl"> 【做题】SRM701 Div1 Hard - FibonacciStringSum——数学和式&矩阵快速幂 - 11GX
首页 > 【做题】SRM701 Div1 Hard - FibonacciStringSum——数学和式&矩阵快速幂

【做题】SRM701 Div1 Hard - FibonacciStringSum——数学和式&矩阵快速幂

原文链接 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 ]

我们尝试化简:

[ egin{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 {achoose 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 
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;
}



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

转载于:https://www.cnblogs.com/cly-none/p/SRM701Div1C.html

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  • 描述 “托普利兹矩阵”是指如果从左上角到右下角的同一条主斜线上每个元素都相等的矩阵. 给定一个M x N矩阵,判断是否为“托普利兹矩阵”. matrix 是一个二维整数数组.matrix 的行列范围都为 [1, 20].matrix[i][j] 的整数取值范围为[0, 99].样例 样例 1: 输入: matrix = [[1,2,3...

  • 需要用到概率论的容斥定理以及计算1 ^ 4 + 2 ^ 4 + ……+ n ^ 4的计算公式1^4+2^4+……+n^4=n(n+1)(2n+1)(3n^2+3n-1)/30   #pragma comment(linker,"/STACK:1024000000,1024000000") #include #incl...