链接:https://www.nowcoder.com/questionTerminal/79c639e02bc94e6b919e3372c8e1dc5e
来源:牛客网
- 时间限制:1秒空间限制:32768K
- 算法知识视频讲解
小易拥有一个拥有魔力的手环上面有n个数字(构成一个环),当这个魔力手环每次使用魔力的时候就会发生一种奇特的变化:每个数字会变成自己跟后面一个数字的和(最后一个数字的后面一个数字是第一个),一旦某个位置的数字大于等于100就马上对100取模(比如某个位置变为103,就会自动变为3).现在给出这个魔力手环的构成,请你计算出使用k次魔力之后魔力手环的状态。
输入描述:
输入数据包括两行: 第一行为两个整数n(2 ≤ n ≤ 50)和k(1 ≤ k ≤ 2000000000),以空格分隔 第二行为魔力手环初始的n个数,以空格分隔。范围都在0至99.
输出描述:
输出魔力手环使用k次之后的状态,以空格分隔,行末无空格。
示例1
输入
3 2 1 2 3
输出
8 9 7
package go.jacob.day913;
import java.util.Scanner;
/**
* [编程题]魔力手环
*
* @author Jacob 利用矩阵快速幂求解
*/
public class Demo5 {
/*
* 思路参考:@minnnng 如输入A = [[1, 2, 3]], k = 2。
* 我们可以构造一个这样的矩阵B(代码中的mul矩阵)[[1, 0,
* 1], [1, 1, 0], [0, 1, 1]], 使得A*Bk相当于A转换k次后的样子。
* 所以原问题就变成求矩阵快速幂。快速幂取余中,a k
* % c = (a % c)k % c。 类似问题:O(log(n))复杂度的Fibonacci数列,
*
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), k = sc.nextInt();
// 将arr表示成矩阵而不是数组,是为了方便后续计算
int[][] arr = new int[n][n];
for (int i = 0; i < n; i++) {
arr[0][i] = sc.nextInt();
}
// 构造矩阵
int[][] mat = new int[n][n];
for (int i = 0; i < n; i++) {
mat[i][i] = 1;
// 取模
mat[(i + 1) % n][i] = 1;
}
// 模拟矩阵运算
for (; k > 0; k >>= 1) {
//说明最后一位为1,进行右移时会丢失精度
if ((k & 1) == 1)
arr = solve(arr, mat);
mat = solve(mat, mat);
}
System.out.print(arr[0][0]);
for(int i=1;i<arr.length;i++)
System.out.print(" "+arr[0][i]);
}
// 矩阵相乘
private static int[][] solve(int[][] mat1, int[][] mat2) {
int n = mat1.length;
int[][] res = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
if (mat1[i][k] == 0 || mat2[k][j] == 0)
continue;
res[i][j] += mat1[i][k] * mat2[k][j];
}
if(res[i][j]>=100)
res[i][j]%=100;
}
}
return res;
}
}