【做题】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
\]
我们尝试化简:
\[
\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;
}

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

原文地址:https://www.cnblogs.com/cly-none/p/SRM701Div1C.html

时间: 2024-10-16 01:04:41

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

hdu 5171 GTY&#39;s birthday gift(数学,矩阵快速幂)

题意: 开始时集合中有n个数. 现在要进行k次操作. 每次操作:从集合中挑最大的两个数a,b进行相加,得到的数添加进集合中. 以此反复k次. 问最后集合中所有数的和是多少. (2≤n≤100000,1≤k≤1000000000) 思路: 写出来发现是要求Fibonaci的前n个数的和. Fibonaci是用矩阵快速幂求的,这个也可以. [Sn,Fn,Fn-1]=[某个矩阵]*[Sn-1,Fn-1,Fn-2] [S2,F2,F1]=[2,1,1] 然后写,,, 这个代码有些繁琐,应该把矩阵操作单独

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

从今天开始就有各站网络赛了 今天是ccpc全国赛的网络赛 希望一切顺利 可以去一次吉大 希望还能去一次大连 题意: 很明确是让你求Sn=[a+sqrt(b)^n]%m 思路: 一开始以为是水题 暴力了一发没过 上网看了一下才知道是快速幂 而且特征方程的推导简直精妙 尤其是共轭相抵消的构造 真的是太看能力了 (下图转自某大神博客) 特征方程是C^2=-2*a*C+(a*a-b) 然后用快速幂求解 临时学了下矩阵快速幂 从这道题能看出来 弄ACM真的要数学好 这不是学校认知的高数 线代 概率分数 而

[BZOJ 2326][HNOI 2011]数学作业(矩阵快速幂)

蒟蒻线性代数太烂了...这个逼题居然卡了半天才做出来,弱的不行啊... 矩阵快速幂,把n这个len位数拆成len次分段快速幂就可以了. 注意取模的数字m<=1e9,所以矩阵乘法运算时要先对乘数取模,防止中间运算结果太大溢出,坑爹啊 代码: #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #d

(中等) 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 there is an airport is located. Also, there is the only one airline, which makes m flights. Unfortunately, to use them, you need to be a regular custo

HDU4565 So Easy! 矩阵快速幂外加数学

easy 个屁啊,一点都不easy,题目就是要求公式的值,但是要求公式在最后的取模前的值向上取整,再取模,无脑的先试了快速幂 double  fmod来做,结果发现是有问题的,这题要做肯定得凑整数,凑整  题目给 a+√b 那么加上a-√b就可以了,可是这样加上后面怎么处理还得减去,想了半年也想不出来, 原来用了负数的共轭思想,还有就是题目给的b的范围 是 ((a-1)*(a-1),a*a),所以 a-√b的值的 无论多少次方 的值都是小于1的,所以对于原式子 改装成 ((a + √b) ^n+

软件能力认证题---拼图(状态压缩DP+矩阵快速幂)

题意: 给定n*m的棋盘(1<=N<=10^15, 1<=M<=7),用L型骨牌(田字型任意去掉一个口)完全覆盖它,问有多少种解. 思路:m的范围只有1<=M<=7,显然状压DP.但是N的最大值到10^15,只能用快速幂了. 状态表示:0代表此处留空,1代表此处被填满.01序列压缩成一个int型来表示一行的填放情况.(例如:状态为4,则代表100,即第一列填满,第二第列三空) 边界条件: 其中, t = 2^M  代表将前i-1行填满,且第i行放置了状态s时的总方案数.

POJ 3613 Cow Relays (Floyd + 矩阵快速幂 + 离散化 神题!)

Cow Relays Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5611   Accepted: 2209 Description For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout

HDU——1005Number Sequence(模版题 二维矩阵快速幂+操作符重载)

Number Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 148003    Accepted Submission(s): 35976 Problem Description A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A

HDU 5863 cjj&#39;s string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但是 m 很小的时候 发现此题DP并不合适.于是想可能是某种组合数学的问题可以直接公式算 看到题解的我.恍然大悟.对于这种数据.可以考虑一下矩阵快速幂优化的DP 首先要想到线性递推的 DP 式子 最直观的想法就是 dp[i][j] = 到第 i 个位置为止.前面最长匹配长度为 j 的方案数 但是如果仔