传送门:【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 |
| 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 ; }