【COGS】1471 [SRM 377]外星语言 矩阵快速幂

传送门:【COGS】1471 [SRM 377]外星语言


题目分析:题目中元音和辅音可以视为两个不相干的元素,假设f(n) 为长度为n的元音,能构成的种类,g(n)为长度为n的辅音,能构成的种类,设s(n)为元音和辅音长度各不能超过n能构成的种类(注意元音一定要辅音的后面,这就给了一个很大的限制条件),那么s(n) = sum{ f( i ) * g( j ) | 1 <= i , j <= n }。

那么我们只要分别求出Sf( n ) = sum{ f( i ) } , Sg( n ) = sum{ f( j ) },则ans = Sf( n ) * Sg( n )

现在我们怎么求Sf( n )?

我们先找一下递推式:f1( i ) = f1( i - 1 ) * p,f2( i ) = f1( i - 1 ) * p * i,f( i ) = f1( i ) + f2( i ),其中f2( i )是带重音后的种类数。

最后可以推出Sf( n ) = ( p^1 + p^2 + p^3 + ... + p^n ) + ( p^1 + 2*p^2 + 3*p^3 + ... + n*p^n )(分开来写是有原因的)

令x( i ) = p^1+p^2+...+p^i,y( i ) = p^1+2*p^2+...+i*p^i。

则假设我们已知x( i )和y( i ),我们要推y( i + 1 ),我们该构造怎样的一个矩阵?

可以是如下的方式:

[ p p p ] * | y( i ) |
            | x( i ) |
            |    1   |

如果得到的y( i + 1 )放在第一列,则x( i + 1 )则无法推出,于是我们放到第二列,但放到第二列以后我们的位置又要保证他一直是1,所以将x( i ) 与 1的行互换,于是得到了最终的矩阵:

| p p p |   | p^i y(i)  i*p^i |   | p^(i+1) y(i+1) (i+1)*p^(i+1) |
| 0 1 0 | * |  0    1     0   | = |    0       1         0       |
| 0 p p |   |  0  x(i)   p^i  |   |    0    x(i+1)    p^(i+1)    |
最左边的矩阵就是最初的矩阵A,A^n即Sf(n)。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )

const int MAXN = 3 ;
int mod , p , q , n ;

struct Matrix {
	LL mat[MAXN][MAXN] ;
	int n ;
	Matrix () {}
	Matrix ( int n ) : n ( n ) {}
	void clear () {
		clr ( mat , 0 ) ;
	}
	void init () {
		rep ( i , 0 , n ) rep ( j , 0 , n ) mat[i][j] = ( i == j ) ;
	}
	Matrix operator * ( const Matrix& a ) const {
		Matrix c ( n ) ;
		c.clear () ;
		rep ( i , 0 , n ) rep ( j , 0 , n ) rep ( k , 0 , n ) {
			c.mat[i][j] = ( c.mat[i][j] + mat[i][k] * a.mat[k][j] ) % mod ;
		}
		return c ;
	}
	
} ;

Matrix pow ( Matrix& a , int b ) {
	Matrix res ( a.n ) , tmp = a ;
	res.init () ;
	while ( b ) {
		if ( b & 1 ) res = res * tmp ;
		tmp = tmp * tmp ;
		b >>= 1 ;
	}
	return res ;
}

LL cal ( int n , int x ) {
	Matrix A ( 3 ) ;
	A.clear () ;
	A.mat[0][0] = x ; A.mat[0][1] = x ; A.mat[0][2] = x ;
	A.mat[1][0] = 0 ; A.mat[1][1] = 1 ; A.mat[1][2] = 0 ;
	A.mat[2][0] = 0 ; A.mat[2][1] = x ; A.mat[2][2] = x ;
	Matrix res = pow ( A , n ) ;
	return ( res.mat[0][1] + res.mat[2][1] + 1 ) % mod ;
}

void solve () {
	scanf ( "%d%d%d%d" , &p , &q , &n , &mod ) ;
	printf ( "%I64d\n" , ( cal ( n , p ) * cal ( n , q ) - 1 ) % mod ) ;
}

int main () {
	freopen ( "alienlanguage.in" , "r" , stdin ) ;
	freopen ( "alienlanguage.out" , "w" , stdout ) ;
	solve () ;
	return 0 ;
}


你可能感兴趣的:(cogs)