[TJOI2010] 天氣預報 題解

Supor__Shoop發表於2024-09-27

分析一下題目,大致意思就是給定一組常數 \(a_i\),然後有一個遞推式 \(w_i=\sum _{j=1}^{n} w_{i-j}\times a_{j}\),讓你求出 \(w_m\) 對於 \(4147\) 取模的值。

根據這個 \(1\leq m\leq 10^7\) 的恐怖範圍,姑且算到了 \(O(m)\) 的時間複雜度。但是觀察一下這個遞推式,發現 \(O(m)\) 跑不出來。於是乎我們自然就想到了使用矩陣快速冪最佳化。

我們先構造出初始矩陣:

\[st= \left( \begin{matrix} w_n & w_{n-1} & \dots & w_2 & w_1 \end{matrix} \right) \]

接著我們需要將其進行轉移,得到新的 \(w_{n+1}\) 的值,最後使用快速冪求出 \(w_{m}\) 的值。那麼很明顯,對於這個轉移矩陣的第一列肯定是從 \(w_n\)\(w_{n+1}\) 的所有常數 \(a_i\),而後面的 \(n-1\) 項我們只需要直接賦值就可以了。整個式子差不多就是這個樣子:

\[\left( \begin{matrix} w_{n+1} & w_{n} & \dots & w_3 & w_2 \end{matrix} \right) = \left( \begin{matrix} w_n & w_{n-1} & \dots & w_2 & w_1 \end{matrix} \right) \times \left( \begin{matrix} a_1 & 1 & 0 & \dots & 0 & 0 \\ a_2 & 0 & 1 & \dots & 0 & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ a_{n-2} & 0 & 0 & \dots & 1 & 0 \\ a_{n-1} & 0 & 0 & \dots & 0 & 1 \\ a_n & 0 & 0 & \dots & 0 & 0 \end{matrix} \right) \]

然後我們根據快速冪,把最後的矩陣直接算出來:

\[\left( \begin{matrix} w_m & w_{m-1} & \dots & w_{m-n+2} & w_{m-n+1} \end{matrix} \right) = \left( \begin{matrix} w_n & w_{n-1} & \dots & w_2 & w_1 \end{matrix} \right) \times \left( \begin{matrix} a_1 & 1 & 0 & \dots & 0 & 0 \\ a_2 & 0 & 1 & \dots & 0 & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ a_{n-2} & 0 & 0 & \dots & 1 & 0 \\ a_{n-1} & 0 & 0 & \dots & 0 & 1 \\ a_n & 0 & 0 & \dots & 0 & 0 \end{matrix} \right) ^{m-n+1} \]

這樣我們取這個矩陣的 \(w_m\) 輸出來就可以了。

程式碼如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=4147;
const int MAXN=105; 
int n,m;
int st[MAXN],a[MAXN];
int fr[MAXN][MAXN];
void mul(long long f[105],long long a[105][105])
{
    long long c[105];
    memset(c,0,sizeof(c));
    for(int j=0;j<n;j++)
    {
        for(int k=0;k<n;k++)    c[j]=(c[j]+(long long)f[k]*a[k][j])%MOD;
    }
    memcpy(f,c,sizeof(c));
}
void mulself(long long a[105][105])
{
    long long c[105][105];
    memset(c,0,sizeof(c));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            for(int k=0;k<n;k++)    c[i][j]=(c[i][j]+(long long)a[i][k]*a[k][j])%MOD;
        }
    }
    memcpy(a,c,sizeof(c));
}
signed main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)	cin>>st[n-i-1];
	for(int i=0;i<n;i++)	cin>>a[i];
	for(int i=1;i<n;i++)	fr[i][i-1]=1;
	for(int i=0;i<n;i++)	fr[i][n-1]=a[n-i-1];
	int sum=m-n;
	while(sum)
	{
		if(sum&1)	mul(st,fr);
		sum>>=1;
		mulself(fr);
	}
	cout<<st[n-1];
	return 0;
}

相關文章