zoukankan      html  css  js  c++  java
  • 蓝桥杯 奇异的虫群 矩阵快速幂

    问题描述

      在一个奇怪的星球上驻扎着两个虫群A和B,它们用奇怪的方式繁殖着,在t+1时刻A虫群的数量等于t时刻A虫群和B虫群数量之和,t+1时刻B虫群的数量等于t时刻A虫群的数量。由于星际空间的时间维度很广阔,所以t可能很大。OverMind 想知道在t时刻A虫群的数量对 p = 1,000,000,007.取余数的结果。当t=1时 A种群和B种群的数量均为1。
    输入格式
      测试数据包含一个整数t,代表繁殖的时间。
    输出格式
      输出一行,包含一个整数,表示对p取余数的结果
    样例输入
    10
    样例输出
    89
    样例输入
    65536
    样例输出
    462302286
    数据规模和约定
      对于50%的数据 t<=10^9
      对于70%的数据 t<=10^15
      对于100%的数据 t<=10^18
    解题思路:看出来是求斐波那契数列第n项了,不过数据范围太大,用O(n)的时间复杂度一定超时。尝试性的提交了一下,看看能不能过几个小数据的样例。
     1 //超时代码 
     2 #include <bits/stdc++.h>
     3 using namespace std; 
     4 const int mod = 1000000007;
     5 typedef long long ll;
     6 int main() {
     7     ll n;
     8     cin >> n;
     9     ll a = 1;
    10     ll b = 1;
    11     ll ans = 1;
    12     for (int i = 2; i <= n; i++) {
    13         ans = (a % mod + b % mod) % mod;
    14         a = b;
    15         b = ans;
    16     }
    17     cout << ans << endl;
    18     return 0;
    19 }

    结果一个样例没过,下载测试数据发现基本都是10^8级别。

    然后学到这道题是矩阵快速幂的模板题目,时间复杂度O(logn)。

    先复习一下一般的快速幂。

    预备知识:快速幂的百度百科:https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E5%B9%82/5500243?fr=aladdin

    最一般的快速幂模板:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod = 1000000007;
     5 ll quick_pow(ll x, ll y, ll c) {
     6     ll ans = 1;
     7     while (y) {
     8         if (y & 1) {
     9             ans = (ans * x) % c;
    10         }
    11         x = (x * x) % c;
    12         y >>= 1;
    13     }
    14     return ans;
    15 }
    16 int main() {
    17     ll x, y, ans;
    18     cin >> x >> y;
    19     ans = quick_pow(x, y, mod);
    20     cout << ans << endl;
    21     return 0;
    22 }

     然后是利用快速乘法优化一下,就是将quick_pow复制一下改名为quick_mul,把ans改为0,所有的乘号改为加号,用于把普通的大数a乘以大数a加速。不过一般用不到,先贴出来备忘,万一哪天用到了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod = 1000000007;
     5 ll quick_mul(ll x, ll y, ll r) {
     6     ll ans = 0;
     7     while (y) {
     8         if (y & 1) {
     9             ans = (ans + x) % r;
    10         }
    11         x = (x + x) % r;
    12         y >>= 1;
    13     }
    14     return ans;
    15 }
    16 ll quick_pow(ll x, ll y, ll r) {
    17     ll ans = 1;
    18     while (y) {
    19         if (y & 1) {
    20             ans = quick_mul(ans, x, r);
    21         }
    22         x = quick_mul(x, x, r);;
    23         y >>= 1;
    24     }
    25     return ans;
    26 }
    27 int main() {
    28     ll x, y, ans;
    29     cin >> x >> y;
    30     ans = quick_pow(x, y, mod);
    31     cout << ans << endl;
    32     return 0;
    33 }

    以前没有学过矩阵快速幂的模板,本着学习新知识,分析网上搜来的其他模板整理出一个自己惯用的模板的原则,写出了我很满意的第一版矩阵快速幂模板。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int mod = 1000000007;
     4 typedef long long ll;
     5 struct Matrix {
     6     ll a[2][2];
     7     Matrix() {
     8         memset(a, 0, sizeof a);
     9     }
    10 };
    11 Matrix mul(Matrix A, Matrix B) { //返回矩阵A乘矩阵B
    12     Matrix C; //C矩阵来存答案 
    13     for (int i = 0; i < 2; i++) {
    14         for (int k = 0; k < 2; k++) {
    15             for (int j = 0; j < 2; j++) {
    16                 C.a[i][j] += (A.a[i][k] % mod * B.a[k][j] % mod) % mod;
    17             }
    18         }
    19     }
    20     return C; //返回新矩阵 
    21 }
    22 Matrix pow_mod(Matrix A, int n) { //返回矩阵A的n次方 
    23     Matrix B; //存储答案 
    24     for (int i = 0; i < 2; i++) { //初始化为单位矩阵 
    25         for (int j = 0; j < 2; j++) {
    26             B.a[i][j] = (i == j ? 1 : 0);
    27         }
    28     } 
    29     while (n) { //同一般的快速幂 
    30         if (n & 1) {
    31             B = mul(B, A);
    32         }
    33         A = mul(A, A);
    34         n >>= 1;    
    35     }
    36     return B;
    37 }
    38 int main() {
    39     int n;
    40     cin >> n;
    41     Matrix A;
    42     A.a[0][0] = A.a[0][1] = A.a[1][0] = 1; //初始化T矩阵 
    43     A = pow_mod(A, n - 1);
    44     cout << (A.a[0][0] + A.a[0][1]) % mod << endl;
    45     return 0;
    46 }

    结果提交后发现只有50分,查看样例后发现数据量太大时会超时,怀疑是调用c++结构体里的构造函数比较耗时。不过第一版模板的思路逻辑还是挺好的,适合用来复习矩阵快速幂算法。

    然后AC的第二版代码,参考自https://blog.csdn.net/cplutoy/article/details/104268207

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int p = 1000000007;
     4 typedef long long ll;
     5 struct Mat {
     6     ll m[2][2];
     7 } ans, base; //ans为答案矩阵, base为需要求次方的矩阵 
     8 Mat Mul(Mat x, Mat y) { //返回矩阵x乘以矩阵y的矩阵 
     9     Mat c;
    10     for (int i = 0; i < 2; i++) {
    11         for (int j = 0; j < 2; j++) {
    12             c.m[i][j] = 0;
    13             for (int k = 0; k < 2; k++) {
    14                 c.m[i][j] += (x.m[i][k] % p * y.m[k][j] % p) % p;
    15             }
    16         }
    17     }
    18     return c;
    19 }
    20 void quick_pow(ll n) { //求base的n-1次方 
    21     while (n) { //同一般的快速幂 
    22         if (n & 1) {
    23             ans = Mul(ans, base);
    24         }
    25         base = Mul(base, base);
    26         n >>= 1;
    27     }
    28 }
    29 int main() {
    30     ll n;
    31     cin >> n;
    32     ans.m[0][0] = 1, ans.m[0][1] = 0, ans.m[1][0] = 0, ans.m[1][1] = 1; //初始化ans为单位矩阵,
    33     base.m[0][0] = 1, base.m[0][1] = 1, base.m[1][0] = 1, base.m[1][1] = 0; //将base初始化为要求n次幂的矩阵
    34     quick_pow(n - 1);
    35     cout << (ans.m[0][0] + ans.m[0][1]) % p << endl;
    36     return 0;
    37 }
  • 相关阅读:
    MOSS 2007(Designer) 自定义列表表单开发笔记1(表单字段控件格式化)
    不使用第三个变量,怎么交换两个变量的值?
    AT指令介绍
    转:iis 支持wap
    WAP传输协议
    计算生肖
    下载文件 转
    彩信MO,MT的业务流程(转)
    最详细AT指令
    WML标签手册
  • 原文地址:https://www.cnblogs.com/fx1998/p/12618125.html
Copyright © 2011-2022 走看看