HZNUOJ B_M的忧虑 矩阵快速幂

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),我们想到用循环来暴力求解,但是因为数据范围给的很大,所以暴力求解是肯定行不通的,即乘积求和,所以我们可以(很自然)联想到转化为矩阵求和(这个很自然也不一定真的很自然),我们画几个矩阵可以找到一个推导公式,那么我们就可以用矩阵快速幂来求和
上图:
emmm,算是推导过程吧
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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值