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掉了,最后才知道这个是用矩阵的快速幂做的。。。。
呃呃呃,所以这个东东该怎么写呢。。。。
设两个矩阵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;
}