zoukankan      html  css  js  c++  java
  • 【做题】SRM701 Div1 Hard

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

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

  • 相关阅读:
    oracle中add_months()函数总结
    Oracle总结之plsql编程(基础九)
    Oracle总结之plsql编程(基础八)
    java调用存储过程
    Oracle总结之plsql编程(基础七)
    Python 變量 Variable 動態綁定
    Python 類和對象 Class vs Object
    Python 元組 Tuple
    Python 字典 Dictionary
    Python 列表 List
  • 原文地址:https://www.cnblogs.com/cly-none/p/SRM701Div1C.html
Copyright © 2011-2022 走看看