B_M的忧虑


链接: link.

题目

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

题解

这道题数据量很大有1e18,一开始以为是找规律的题目,就一脑门找重复的数组长度,一直找到五万多的长度但还是wa掉了,最后才知道这个是用矩阵的快速幂做的。。。。

Alt
呃呃呃,所以这个东东该怎么写呢。。。。
设两个矩阵A(1 * n),B( n * n) , s.t. A*B=C

矩阵A存储n天内的体重,用于计算下一天的体重
矩阵B存储an的值,和由1,0组成的矩阵,用于计算
可以通过线代的方式计算C=A*B,使得C的第一项为n+1天的重量,然后将矩阵A中的其余体重迁移,额,大概是这样

上个图给你们看看,有点丑陋别介意

在这里插入图片描述
总体意思大致就是这样,如果还是看不懂就看代码吧

代码

typedef long long ll;
const double eps = 1e-8;
const double PI = 3.14;
const int maxn = 1e2 + 20;
const int Maxn = 1e8;
const int inf = 0x3f3f3f3f;
const int mod = 193;

ll n, m;
int w[maxn], a[maxn];
struct mat {
	int a[maxn][maxn];
};
mat mat_mul(mat x, mat y) {//普通的矩阵相乘
	mat res;
	memset(res.a, 0, sizeof res.a);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n; k++) {
				res.a[i][j] += x.a[i][k] * y.a[k][j];
				res.a[i][j] %= mod;
			}
		}
	}
	return res;
}
mat mat_mul2(mat y, mat x) {//普通的矩阵相乘
	mat res;
	memset(res.a, 0, sizeof res.a);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= 1; j++) {
			for (int k = 1; k <= n; k++) {
				res.a[i][j] += x.a[i][k] * y.a[k][j];
				res.a[i][j] %= mod;
			}
		}
	}
	return res;
}
ll mat_pow(ll m) {
	mat c, res;
	memset(res.a, 0, sizeof res.a);
	memset(c.a, 0, sizeof c.a);
	for (ll i = 1; i <= n; i++) {
		res.a[i][1] = w[n - i + 1];//将前n天的体重赋值给res.a
	}
	for (ll i = 1; i <= n; i++) {
		for (ll j = 1; j <= n; j++) {
			if (i == 1)c.a[i][j] = a[j];//c.a第一行输入常数组a
			else {
				if (j == i - 1)c.a[i][j] = 1;//这里就是上图中的1,0矩阵
			}
		}
	}
	while (m) {//因为设置矩阵A只有一行,矩阵相乘的函数分开写了
		if (m & 1)res = mat_mul2(res, c);
		c = mat_mul(c, c);//将矩阵B自己相乘,使得结果为1,2,4,8...
		m = m >> 1;
	}//重点:上面四行就是矩阵的快速幂,具体百度
	return res.a[1][1];
}

int main() {
	scanf("%lld %lld", &n, &m);
	for (ll i = n; i >= 1; i--)scanf("%d", &w[i]);//这个体重是从n到1输入的
	for (ll i = 1; i <= n; i++)scanf("%d", &a[i]);//a[i]是输入的计算常数
	ll result = mat_pow(m - n);
	printf("%lld\n", result);
	return 0;
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值