「UVA12183」Top Secret
题目
点这里看题目。
分析
可以发现题目提到的 decryption
其实就是一个线性变换:
\[M=
\begin{bmatrix}
1&R&0&\dots&0&L\\
L&1&R&\dots&0&0\\
0&L&1&\dots&0&0\\
\vdots&\vdots&\vdots&\ddots&\vdots&\vdots\\
0&0&0&\dots&1&R\\
R&0&0&\dots&L&1
\end{bmatrix}
\]
如果直接算矩阵乘法,复杂度是 \(O(n^3\log S)\) 的,无法接受。
注意到 \(M\) 是一个循环矩阵,这意味着我们可以将它拆解为多项式的形式:
\[\begin{aligned}
M&=E^0+RE^1+LE^{n-1}\\
E&=
\begin{bmatrix}
0&1&0&\dots&0&0\\
0&0&1&\dots&0&0\\
0&0&0&\dots&0&0\\
\vdots&\vdots&\vdots&\ddots&\vdots&\vdots\\
0&0&0&\dots&0&1\\
1&0&0&\dots&0&0
\end{bmatrix}
\end{aligned}
\]
对于多项式做循环卷积,接着我们就可以还原出 \(M^S\)。这样复杂度就是 \(O(n^2\log S)\) 的。
小结:循环矩阵比较少见,一般可以将它和多项式结合起来看。
代码
#include <cstdio>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
const int MAXN = 1005;
template<typename _T>
void read( _T &x )
{
x = 0; char s = getchar(); bool f = false;
while( s < '0' || '9' < s ) { f = ( s == '-' ), s = getchar(); }
while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
if( f ) x = -x;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( '-' ), x = -x;
if( 9 < x ) write( x / 10 );
putchar( x % 10 + '0' );
}
int mat[MAXN][MAXN];
int F[MAXN], G[MAXN], tmp[MAXN];
int A[MAXN];
int N, S, L, R, X, mod;
inline int Mul( int x, int v ) { return 1ll * x * v % mod; }
inline int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }
void Convolute( int *ret, const int *P, const int *Q )
{
rep( i, 0, N - 1 ) tmp[i] = 0;
rep( i, 0, N - 1 ) rep( j, 0, N - 1 )
tmp[( i + j ) % N] = Add( tmp[( i + j ) % N], Mul( P[i], Q[j] ) );
rep( i, 0, N - 1 ) ret[i] = tmp[i];
}
int main()
{
int T;
read( T );
while( T -- )
{
read( N ), read( S ), read( L ), read( R ), read( X );
rep( i, 0, N - 1 ) read( A[i] );
mod = 1; rep( i, 1, X ) mod *= 10;
rep( i, 0, N - 1 ) G[i] = F[i] = 0;
G[0] = 1 % mod;
F[0] = 1 % mod, F[1] = R % mod, F[N - 1] = L % mod;
while( S )
{
if( S & 1 ) Convolute( G, G, F );
Convolute( F, F, F ), S >>= 1;
}
for( int i = 0 ; i < N ; i ++ )
for( int k = 0 ; k < N ; k ++ )
mat[k][( i + k ) % N] = G[i];
rep( i, 0, N - 1 )
{
int ans = 0;
rep( j, 0, N - 1 ) ans = Add( ans, Mul( mat[i][j], A[j] ) );
write( ans ), putchar( i == N - 1 ? '\n' : ' ' );
}
}
return 0;
}