HZNUOJB_Mの心配マトリックス高速パワー

B_Mの悩み

説明
B_Mの先輩は体重を減らすのが好きなので、詳細な減量計画を立てました。この計画は詳細すぎるため、将来的に体重を計算することもできます。

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

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

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

入力
データの最初の行は2つの正の整数n(1≤n≤100)とx(1≤x≤1018)であり、2番目の行にはn個の非負の整数(wn、wn-1、...)があります。 w2、w1。3行目には、それぞれa1、a2、...、an-1、anを表すn個の非負の整数があります。(0≤ai、wi≤193)

出力
は、x日目の体重予測結果を表す整数を出力します。結果として、私は193の残りを取る必要があります。なぜ私は理由がわからないのですか

サンプル
入力
2 3
5 8
3 3
の出力
42

**問題の解決策:**問題には∑ni = 1(ai×wx−i)が必要なため、ループを使用して激しく解決することを考えましたが、データ範囲が広いため、暴力的な解決策は絶対に実行できません。つまり、Sumを求める製品であるため、(自然に)行列の合計に変換することを考えることができます(これは自然であり、必ずしも実際には自然ではありません)。いくつかの行列を描画して導出式を見つけ、行列の高速パワーを使用できます。見つけるためにそして上
の写真:
エム、それは派生プロセスですか?
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;
}

おすすめ

転載: blog.csdn.net/qq_40924271/article/details/107879216