欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HZNUOJ B_M的忧虑 矩阵快速幂

程序员文章站 2022-06-22 08:05:21
B_M的忧虑DescriptionB_M学长喜欢减肥,为此他制定出了一个详细的减肥计划。因为这个计划过于详细,所以他甚至可以推算出在未来的某一天自己的体重。 体重的计算规律如下:要计算出自己某一天的体重,需要通过在此之前n天的体重来计算 设wx为第x天的体重,那么wx=∑ni=1(ai × wx−i) , 其中 ai 是给定的常数 现在给出B_M前n天的体重,询问他第x天的体重,题目保证x>nInput输入数据的第一行是两个正整数 n (1≤n≤100)和 x (...

B_M的忧虑

Description
B_M学长喜欢减肥,为此他制定出了一个详细的减肥计划。因为这个计划过于详细,所以他甚至可以推算出在未来的某一天自己的体重。

    体重的计算规律如下:要计算出自己某一天的体重,需要通过在此之前n天的体重来计算

    设wx为第x天的体重,那么wx=∑ni=1(ai × wx−i) , 其中 ai 是给定的常数

    现在给出B_M前n天的体重,询问他第x天的体重,题目保证x>n

Input
输入数据的第一行是两个正整数 n (1≤n≤100)和 x (1≤x≤1018),第二行有 n 个非负整数,分别为 wn,wn−1,…w2,w1。第三行有 n 个非负整数,分别表示 a1,a2,…,an−1,an。(0≤ai,wi≤193)

Output
输出一个整数,表示对第 x 天的体重预测结果。结果需要对193取余,至于为什么我也不知道

Samples
input
2 3
5 9
3 3
output
42

**题解:**因为题目要求∑ni=1(ai × wx−i),我们想到用循环来暴力求解,但是因为数据范围给的很大,所以暴力求解是肯定行不通的,即乘积求和,所以我们可以(很自然)联想到转化为矩阵求和(这个很自然也不一定真的很自然),我们画几个矩阵可以找到一个推导公式,那么我们就可以用矩阵快速幂来求和
上图:
HZNUOJ B_M的忧虑 矩阵快速幂
ac代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<map>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<set>
#include<cctype>
#include<string>
#include<stdexcept>
#include<fstream>
#include<sstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define debug() puts("what the fuck!")
#define dedebug() puts("what the fuck!!!")
#define ll long long
#define ull unsigned long long
#define speed {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); };
using namespace std;
const double PI = acos(-1.0);
const int maxn = 1e2 + 50;
const int N = 110;
const int INF = 0x3f3f3f3f;
const int inf = 0xfffffff;//比INF小,防止累加爆int
const double esp_0 = 1e-6;
const double gold = (1 + sqrt(5)) / 2;
const int mod = 193;
int gcd(int x, int y) {
	return y ? gcd(y, x % y) : x;
}
ll n, x;
int a[maxn], w[maxn];
struct mat {
	int r[maxn][maxn];
};
mat multi(mat x, mat y) {//矩阵乘法 方正*方正
	mat step;
	mem(step.r, 0);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n; k++) {
				step.r[i][j] += x.r[i][k] * y.r[k][j];
				step.r[i][j] %= mod;
			}
		}
	}
	return step;
}
mat multi2(mat x, mat y) {//题意描述的a矩阵*b矩阵
	mat step;
	mem(step.r, 0);
	for (int i = 1; i <= n; i++) {
		for (int k = 1; k <= n; k++) {
			step.r[i][1] += x.r[i][k] * y.r[k][1];
			step.r[i][1] %= mod;
		}		
	}
	return step;
}
ll mat_pow(ll time) {//矩阵快速幂
	mat c, step;
	mem(step.r, 0);
	mem(c.r, 0);
	for (ll i = 1; i <= n; i++) {
		step.r[i][1] = w[n - i + 1];//将w数列读取到step方阵的第一列
	}
	//将a常数列读取到c方阵的第一行
	for (ll i = 1; i <= n; i++) {
		for (ll j = 1; j <= n; j++) {
			//将c方阵的第二列至n列化为单位矩阵,保留前n天w,达到题目所要求的w前n天求和
			if (i == 1)c.r[i][j] = a[j];
			else {
				if (j == i - 1)c.r[i][j] = 1;
			}
		}
	}
	while (time) {//矩阵快速幂  
		if (time & 1)step = multi2(c, step);//将time转化为2进制,如果为1,则进行题目乘法
		c = multi(c, c);//不为1,c方阵快速幂算乘方
		time = time >> 1;
	}
	return step.r[1][1];
}
//void init() {
//	for (int i = 1; i <= n; ++i) {
//		for (int j = 1; j <= n; ++j) {
//			if (i - 1 == j)a.r[i][j] = 1;
//			else a.r[i][j] = 0;
//		}
//	}
//}
int main() {
//	init();
	scanf("%lld %lld", &n, &x);
	for (ll i = n; i >= 1; --i)scanf("%d", &w[i]);
	for (ll i = 1; i <= n; ++i)scanf("%d", &a[i]);
	ll res = mat_pow(x - n);
	printf("%lld\n", res);
	return 0;
}

本文地址:https://blog.csdn.net/qq_40924271/article/details/107879216

相关标签: acm 算法