魔力手环(快速幂求解)

题目链接:https://www.nowcoder.com/questionTerminal/79c639e02bc94e6b919e3372c8e1dc5e

小易拥有一个拥有魔力的手环上面有n个数字(构成一个环),当这个魔力手环每次使用魔力的时候就会发生一种奇特的变化:每个数字会变成自己跟后面一个数字的和(最后一个数字的后面一个数字是第一个),一旦某个位置的数字大于等于100就马上对100取模(比如某个位置变为103,就会自动变为3).现在给出这个魔力手环的构成,请你计算出使用k次魔力之后魔力手环的状态。

输入描述:
输入数据包括两行:
第一行为两个整数n(2 ≤ n ≤ 50)和k(1 ≤ k ≤ 2000000000),以空格分隔
第二行为魔力手环初始的n个数,以空格分隔。范围都在0至99.
输出描述:
输出魔力手环使用k次之后的状态,以空格分隔,行末无空格。
输入例子:
3 2
1 2 3
输出例子:
8 9 7

思路:n个数的环进行移动相加,考虑到矩阵行、列变换可以完成这种移动和相加,于是构造出快速幂矩阵,快速幂矩阵M和原矩阵S相乘得到一次移动的结果,那么F(n+1) = M^n*S(这里的幂和乘法是矩阵的运算),很容易得到如下递推示例:

[[1 1 0] [0 1 1] [1 0 1]]*[[a][b][c]] = [[a+b][b+c][c+a]], 如此,已经确定了快速幂矩阵M,那么就要考虑如何相乘得到最快的幂求解速度。建议参看这篇博客

代码如下:(算法复杂度为O(n^3*log(k)))

#include<iostream>
#include<cstring>
using namespace std;

int main(){
    int n,k;
    cin >> n >> k;
    int d[n];//存放结果
    for(int i=0;i<n;++i) {
        cin >> d[i];
    }
    //构造快速幂矩阵
    int Mul[n][n];
    for(int i=0;i<n-1;++i) {
        fill(Mul[i],Mul[i]+n,0);
        Mul[i][i] = 1;
        Mul[i][i+1] = 1;
    }
    fill(Mul[n-1],Mul[n-1]+n,0);
    Mul[n-1][0] = 1;
    Mul[n-1][n-1] = 1;
    //转化为2进制,进行二分搜索
    while(k) {
        if(k&1) {
            int temp[n];
            fill(temp, temp+n, 0);
            for(int i=0;i<n;++i) {
                for(int j=0;j<n;++j) {
                    temp[i] += (Mul[i][j]*d[j]);
                    temp[i] = temp[i]%100;
                }
            }
            memcpy(d, temp, sizeof(d));
        }
        k = k>>1;
        int temp[n][n];
        for(int i=0;i<n;++i) {
            fill(temp[i],temp[i]+n,0);
        }
        for(int i=0;i<n;++i) {
            for(int j=0;j<n;++j) {
                for(int k=0;k<n;++k) {
                    temp[i][j]+=Mul[i][k]*Mul[k][j];//二维矩阵相乘
                }
                temp[i][j] %= 100;//快速幂取余中,a^k % c =  (a % c)^k % c
            }
        }
        for(int i=0;i<n;++i) {
            memcpy(Mul[i],temp[i],sizeof(Mul[i]));
        }
    }
    //输出结果
    for(int i=0;i<n-1;++i) {
        cout << d[i] << ‘ ‘;
    }
    cout << d[n-1] << endl;
    return 0;
}

矩阵快速幂的总结(更多问题->熟练掌握)

时间: 2024-12-05 06:41:49

魔力手环(快速幂求解)的相关文章

#斐波那契数列用矩阵快速幂求解f(n)#

通常情况下,斐波那契数列第n项可以通过递归求解或者直接求解但当n非常大的时候,求解f(n)将显得非常困难下面利用矩阵以及快速幂的方法在logn复杂度内求解 则可以运用快速幂来求解矩阵高次幂,复杂度降为logn 来自为知笔记(Wiz)

快速幂求解

顾名思义,快速幂就是快速算底数的n次幂.其时间复杂度为 O(log?N), 与朴素的O(N)相比效 用法:用于求解 a 的 b 次方,而b是一个非常大的数,用O(n)的复杂度会超时.那么就需要这个算法,注意它不但可以对数求次幂,而且可用于矩阵快速幂. 把b转换成二进制数,该二进制位数有logb位:该二进制数第i位的权为2i-1 例如:      11的二进制是1011 11 = 23×1 + 22×0 + 21×1 + 2o×1 因此,我们将a11转化为算

矩阵乘法(四):分析问题,确定递推式,采用矩阵快速幂求解

应用矩阵快速幂运算可以解决递推问题.在实际应用中,有时候题目并没有直接给出递推式,需要认真分析问题,找出递推式,然后再利用矩阵快速幂运算加快问题的求解. [例1]程序阅读理解. 有如下的C语言程序: #include <stdio.h>int main(){     int n,m,f,i;     while(scanf("%d%d",&n,&m)!=EOF)     {           f=0;           for(i=1;i<=n;i

斐波那契数列以及斐波那契数列的衍生形式 利用矩阵快速幂求解

一.斐波那契数列F[n]=F[n-1]+F[n-2] 可转换为矩阵s[1,1,1,0]的n次幂的矩阵的s[0][1]的值 矩阵的幂次方 可通过 奇判断及进制移位提高时间效率 位与运算 n&1表示的意思:取二进制n的最末位,二进制的最末位为零表示n为哦数,为1表示奇数,即等价于n%2 n>>1 是将n的二进制向右移动一位, n>>=1 即把移动后的值赋给n 题目:求斐波那契数列F[n]%10000(取模) #include <cstdio> #include &l

[板子]矩阵快速幂求解斐波那契

在斐波那契数列之中 f[i] = 1*f[i-1]+1*f[i-2]  f[i-1] = 1*f[i-1] + 0*f[i-2]; 即 所以 就这两幅图完美诠释了斐波那契数列如何用矩阵来实现. 摘自:http://blog.csdn.net/nyist_tc_lyq/article/details/52981353 #include<bits/stdc++.h> #define LL long long using namespace std; const long long pi=10000

HDU1588-Gauss Fibonacci(矩阵快速幂+等比数列二分求和)

题目链接 题意:g(x) = k * x + b.f(x) 为Fibonacci数列.求f(g(x)),从x = 1到n的数字之和sum,并对m取模. 思路: 设A = |(1, 1),(1, 0)| sum = f(b) + f(k + b) + f(2k + b)...+f((n-1)k + b) (f(x) 为Fibonacci数列) sum = A^b + A^(k + b) + A^(2k + b)...+ A^((n-1)k + b) sum = A^b(1 + A^k + A^2k

UVA 10655 - Contemplation! Algebra(矩阵快速幂)

UVA 10655 - Contemplation! Algebra 题目链接 题意:给定p, q, n代表p=a+b,q=ab求an+bn 思路:矩阵快速幂,公式变换一下得到(an+bn)(a+b)=an+1+bn+1+ab(an?1+bn?1),移项一下得到an+1+bn+1=(an+bn)p?q(an?1+bn?1) 这样就可以用矩阵快速幂求解了 代码: #include <stdio.h> #include <string.h> long long p, q, n; str

HDU 2842 Chinese Rings(矩阵快速幂+递推)

题目地址:HDU 2842 这个游戏是一个九连环的游戏. 假设当前要卸下前n个环.由于要满足前n-2个都卸下,所以要先把前n-2个卸下,需要f(n-2)次.然后把第n个卸下需要1次,然后这时候要卸下第n-1个,然后此时前n-2个都已经被卸下了.这时候把前n-2个都卸下与都装上所需的次数是一样的,因为卸下与装上的规则是一样的.所以又需要f(n-2)次,这时候前n-1个都在上面,卸下前n-1个需要f(n-1)次. 所以,总共需要2*f(n-2)+f(n-1)+1次. 然后构造如下矩阵. 1,2,1

UVA11609 - Teams(组合数学+快速幂)

题目链接 题意:从N个人中选出K个人为一只队伍(1 <= K <= N),每个队伍都要有一个队长,当队长不同时,所代表的队伍也不同,求一共可以选出多少只队伍. 思路:依题目可得ans = sum(i * C(i, n)),化简可得ans = n * sum(C(i, n - 1)) = n * 2 ^ (n - 1).之后用快速幂求解. 代码: #include <iostream> #include <cstdio> #include <cstring>