操作数~矩阵快速幂解法

链接:https://www.nowcoder.com/acm/contest/109/C
来源:牛客网

题目描述

给定长度为n的数组a,定义一次操作为:
1. 算出长度为n的数组s,使得s i= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007;
2. 执行a = s;
现在问k次操作以后a长什么样。

输入描述:

第一行两个整数n,k(1 <= n <= 2000, 0 <= k <= 1,000,000,000);
第二行n个整数表示a数组(0 <= a
i
<= 1,000,000,000)。

输出描述:

一行n个整数表示答案。
示例1

输入

3 1
1 2 3

输出

1 3 6
示例2

输入

5 0
3 14 15 92 6

输出

3 14 15 92 6


这题非常容易找到矩阵A,
1 1 1 1 1
0 1 1 1 1
0 0 1 1 1
0 0 0 1 1
0 0 0 0 1
就是这样的矩阵,
但是要注意一点 n有2000;
所以直接写出这个矩阵不行,压缩一下就OK了

   mat operator * (mat & a) {
        mat ans;
        for (int i = 0 ; i < maxn ; i++) {
                for (int j = 0 ; j <= i ; j++ ) {
                         ans.m[i] = (ans.m[i] + m[j] * a.m[i - j]) % mod;
               }
        }
        return ans;
   }

  由于规律性非常明显,所以可以用一个一维数组存储

  

然后就是常规的矩阵快速幂操作。
不过这题他们说有其他的解法
找规律好像可以做,但是我不会。
只能想到矩阵快速幂的方法
矩阵快速幂有点慢,不过能AC也OK


 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <queue>
 5 #include <cstring>
 6 #include <string>
 7 #include <map>
 8 using namespace std;
 9 const int maxn = 2000;
10 const long  long  mod = 1e9 + 7;
11 typedef long long LL;
12 struct mat {
13     LL m[maxn];
14     mat() {
15         memset(m, 0, sizeof(m));
16     }
17     mat operator * (mat & a) {
18         mat ans;
19         for (int i = 0 ; i < maxn ; i++) {
20             for (int j = 0 ; j <= i ; j++ ) {
21                 ans.m[i] = (ans.m[i] + m[j] * a.m[i - j]) % mod;
22             }
23         }
24         return ans;
25     }
26 };
27 mat modexp(mat a, LL b) {
28     mat ans;
29     for (int i = 0 ; i < maxn ; i++) ans.m[i] = 1;
30     while(b) {
31         if (b & 1 ) ans = ans * a;
32         b = b >> 1;
33         a = a * a;
34     }
35     return ans;
36 }
37 int main() {
38     LL n, k;
39     mat a, b;
40     scanf("%lld%lld", &n, &k );
41     for (int i = 0 ; i < n ; i++) {
42         scanf("%lld", &b.m[i]);
43         a.m[i] = 1;
44     }
45     if (k == 0) {
46         for (int i = 0 ; i < n ; i++) {
47             printf("%lld", b.m[i]);
48             if (i != n - 1) printf(" ");
49             else printf("\n");
50         }
51         printf("\n");
52     } else {
53         a = modexp(a, k - 1);
54         b = b * a;
55         for (int i = 0 ; i < n ; i++) {
56             printf("%lld", b.m[i]);
57             if (i != n - 1) printf(" ");
58             else printf("\n");
59         }
60     }
61     return 0;
62 }

 



转载于:https://www.cnblogs.com/qldabiaoge/p/8995192.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值