题目分析:题目中元音和辅音可以视为两个不相干的元素,假设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 ;
}