杜教BM黑科技
原理未知,主要适用于线性递推式,据说这个BUG级模板可以求线性递推式的第n项,只要手推递推式的前几项,放入模板就能求出第n项,前几项求出的的越多越好,一般推出前8项就可以,但是有的题还是要多几项。
例题 hdu6198 number number number
方法一:找规律 ,输出 f[2*k+3]-1的值就行,f[i]表示斐波那契数列第i项的值。
方法二:黑科技,先打表前几项套模板。
代码1.
#include < bits/ stdc++ . h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 50 ;
const double S = 2.236067 ;
const int p= 998244353 ;
struct mat
{
ll a[ 2 ] [ 2 ] ;
} ;
mat mat_mul ( mat x, mat y)
{
mat res;
memset ( res. a, 0 , sizeof ( res. a) ) ;
for ( int i= 0 ; i< 2 ; i++ )
for ( int j= 0 ; j< 2 ; j++ )
for ( int k= 0 ; k< 2 ; k++ )
res. a[ i] [ j] = ( res. a[ i] [ j] + x. a[ i] [ k] * y. a[ k] [ j] ) % p;
return res;
}
ll mat_pow ( ll n)
{
mat c, res;
c. a[ 0 ] [ 0 ] = c. a[ 0 ] [ 1 ] = c. a[ 1 ] [ 0 ] = 1 ;
c. a[ 1 ] [ 1 ] = 0 ;
memset ( res. a, 0 , sizeof ( res. a) ) ;
res. a[ 0 ] [ 0 ] = 1 ;
res. a[ 0 ] [ 1 ] = 0 ;
while ( n)
{
if ( n& 1 )
res= mat_mul ( res, c) ;
c= mat_mul ( c, c) ;
n= n>> 1 ;
}
return res. a[ 0 ] [ 0 ] ;
}
int main ( )
{
ll n;
while ( scanf ( "%lld" , & n) != EOF )
{
ll ans= mat_pow ( n* 2 + 2 ) - 1 ;
printf ( "%lld\n" , ans) ;
}
}
代码二:(BM)
#include < bits/ stdc++ . h>
using namespace std;
#define rep ( i, a, n) for ( long long i= a; i< n; i++ )
#define per ( i, a, n) for ( long long i= n- 1 ; i>= a; i-- )
#define pb push_back
#define mp make_pair
#define all ( x) ( x) . begin ( ) , ( x) . end ( )
#define fi first
#define se second
#define SZ ( x) ( ( long long) ( x) . size ( ) )
typedef vector< long long> VI ;
typedef long long ll;
typedef pair< long long, long long> PII ;
const ll mod= 998244353 ;
ll powmod ( ll a, ll b)
{
ll res= 1 ;
a%= mod;
assert ( b>= 0 ) ;
for ( ; b; b>>= 1 )
{
if ( b& 1 )
res= res* a% mod;
a= a* a% mod;
}
return res;
}
long long _, n;
namespace linear_seq
{
const long long N = 10010 ;
ll res[ N ] , base[ N ] , _c[ N ] , _md[ N ] ;
vector< long long> Md;
void mul ( ll * a, ll * b, long long k)
{
rep ( i, 0 , k+ k) _c[ i] = 0 ;
rep ( i, 0 , k) if ( a[ i] )
rep ( j, 0 , k)
_c[ i+ j] = ( _c[ i+ j] + a[ i] * b[ j] ) % mod;
for ( long long i= k+ k- 1 ; i>= k; i-- )
if ( _c[ i] )
rep ( j, 0 , SZ ( Md) ) _c[ i- k+ Md[ j] ] = ( _c[ i- k+ Md[ j] ] - _c[ i] * _md[ Md[ j] ] ) % mod;
rep ( i, 0 , k) a[ i] = _c[ i] ;
}
long long solve ( ll n, VI a, VI b)
{
ll ans= 0 , pnt= 0 ;
long long k= SZ ( a) ;
assert ( SZ ( a) == SZ ( b) ) ;
rep ( i, 0 , k) _md[ k- 1 - i] = - a[ i] ;
_md[ k] = 1 ;
Md. clear ( ) ;
rep ( i, 0 , k) if ( _md[ i] != 0 )
Md. push_back ( i) ;
rep ( i, 0 , k) res[ i] = base[ i] = 0 ;
res[ 0 ] = 1 ;
while ( ( 1 ll<< pnt) <= n)
pnt++ ;
for ( long long p= pnt; p>= 0 ; p-- )
{
mul ( res, res, k) ;
if ( ( n>> p) & 1 )
{
for ( long long i= k- 1 ; i>= 0 ; i-- )
res[ i+ 1 ] = res[ i] ;
res[ 0 ] = 0 ;
rep ( j, 0 , SZ ( Md) ) res[ Md[ j] ] = ( res[ Md[ j] ] - res[ k] * _md[ Md[ j] ] ) % mod;
}
}
rep ( i, 0 , k) ans= ( ans+ res[ i] * b[ i] ) % mod;
if ( ans< 0 )
ans+= mod;
return ans;
}
VI BM ( VI s)
{
VI C ( 1 , 1 ) , B ( 1 , 1 ) ;
long long L = 0 , m= 1 , b= 1 ;
rep ( n, 0 , SZ ( s) )
{
ll d= 0 ;
rep ( i, 0 , L + 1 ) d= ( d+ ( ll) C [ i] * s[ n- i] ) % mod;
if ( d== 0 )
++ m;
else if ( 2 * L <= n)
{
VI T = C ;
ll c= mod- d* powmod ( b, mod- 2 ) % mod;
while ( SZ ( C ) < SZ ( B ) + m)
C . pb ( 0 ) ;
rep ( i, 0 , SZ ( B ) ) C [ i+ m] = ( C [ i+ m] + c* B [ i] ) % mod;
L = n+ 1 - L ;
B = T ;
b= d;
m= 1 ;
}
else
{
ll c= mod- d* powmod ( b, mod- 2 ) % mod;
while ( SZ ( C ) < SZ ( B ) + m)
C . pb ( 0 ) ;
rep ( i, 0 , SZ ( B ) ) C [ i+ m] = ( C [ i+ m] + c* B [ i] ) % mod;
++ m;
}
}
return C ;
}
long long gao ( VI a, ll n)
{
VI c= BM ( a) ;
c. erase ( c. begin ( ) ) ;
rep ( i, 0 , SZ ( c) ) c[ i] = ( mod- c[ i] ) % mod;
return solve ( n, c, VI ( a. begin ( ) , a. begin ( ) + SZ ( c) ) ) ;
}
} ;
int main ( )
{
while ( ~ scanf ( "%lld" , & n) )
{
VI vi;
vi. push_back ( 5 ) ;
vi. push_back ( 13 ) ;
vi. push_back ( 34 ) ;
vi. push_back ( 89 ) ;
printf ( "%lld\n" , ( linear_seq: : gao ( vi, n- 1 ) % mod- 1 ) % mod) ;
}
}
注意的是,BM模板递推式有所有结果都减一的话,建议先找规律后减一,否则自己需要手打至少前八项。以这个题为例,如果最后减一的话,只需要前四项就够了。
下面是手打前六项的。
#include < bits/ stdc++ . h>
using namespace std;
#define rep ( i, a, n) for ( long long i= a; i< n; i++ )
#define per ( i, a, n) for ( long long i= n- 1 ; i>= a; i-- )
#define pb push_back
#define mp make_pair
#define all ( x) ( x) . begin ( ) , ( x) . end ( )
#define fi first
#define se second
#define SZ ( x) ( ( long long) ( x) . size ( ) )
typedef vector< long long> VI ;
typedef long long ll;
typedef pair< long long, long long> PII ;
const ll mod= 998244353 ;
ll powmod ( ll a, ll b)
{
ll res= 1 ;
a%= mod;
assert ( b>= 0 ) ;
for ( ; b; b>>= 1 )
{
if ( b& 1 )
res= res* a% mod;
a= a* a% mod;
}
return res;
}
long long _, n;
namespace linear_seq
{
const long long N = 10010 ;
ll res[ N ] , base[ N ] , _c[ N ] , _md[ N ] ;
vector< long long> Md;
void mul ( ll * a, ll * b, long long k)
{
rep ( i, 0 , k+ k) _c[ i] = 0 ;
rep ( i, 0 , k) if ( a[ i] )
rep ( j, 0 , k)
_c[ i+ j] = ( _c[ i+ j] + a[ i] * b[ j] ) % mod;
for ( long long i= k+ k- 1 ; i>= k; i-- )
if ( _c[ i] )
rep ( j, 0 , SZ ( Md) ) _c[ i- k+ Md[ j] ] = ( _c[ i- k+ Md[ j] ] - _c[ i] * _md[ Md[ j] ] ) % mod;
rep ( i, 0 , k) a[ i] = _c[ i] ;
}
long long solve ( ll n, VI a, VI b)
{
ll ans= 0 , pnt= 0 ;
long long k= SZ ( a) ;
assert ( SZ ( a) == SZ ( b) ) ;
rep ( i, 0 , k) _md[ k- 1 - i] = - a[ i] ;
_md[ k] = 1 ;
Md. clear ( ) ;
rep ( i, 0 , k) if ( _md[ i] != 0 )
Md. push_back ( i) ;
rep ( i, 0 , k) res[ i] = base[ i] = 0 ;
res[ 0 ] = 1 ;
while ( ( 1 ll<< pnt) <= n)
pnt++ ;
for ( long long p= pnt; p>= 0 ; p-- )
{
mul ( res, res, k) ;
if ( ( n>> p) & 1 )
{
for ( long long i= k- 1 ; i>= 0 ; i-- )
res[ i+ 1 ] = res[ i] ;
res[ 0 ] = 0 ;
rep ( j, 0 , SZ ( Md) ) res[ Md[ j] ] = ( res[ Md[ j] ] - res[ k] * _md[ Md[ j] ] ) % mod;
}
}
rep ( i, 0 , k) ans= ( ans+ res[ i] * b[ i] ) % mod;
if ( ans< 0 )
ans+= mod;
return ans;
}
VI BM ( VI s)
{
VI C ( 1 , 1 ) , B ( 1 , 1 ) ;
long long L = 0 , m= 1 , b= 1 ;
rep ( n, 0 , SZ ( s) )
{
ll d= 0 ;
rep ( i, 0 , L + 1 ) d= ( d+ ( ll) C [ i] * s[ n- i] ) % mod;
if ( d== 0 )
++ m;
else if ( 2 * L <= n)
{
VI T = C ;
ll c= mod- d* powmod ( b, mod- 2 ) % mod;
while ( SZ ( C ) < SZ ( B ) + m)
C . pb ( 0 ) ;
rep ( i, 0 , SZ ( B ) ) C [ i+ m] = ( C [ i+ m] + c* B [ i] ) % mod;
L = n+ 1 - L ;
B = T ;
b= d;
m= 1 ;
}
else
{
ll c= mod- d* powmod ( b, mod- 2 ) % mod;
while ( SZ ( C ) < SZ ( B ) + m)
C . pb ( 0 ) ;
rep ( i, 0 , SZ ( B ) ) C [ i+ m] = ( C [ i+ m] + c* B [ i] ) % mod;
++ m;
}
}
return C ;
}
long long gao ( VI a, ll n)
{
VI c= BM ( a) ;
c. erase ( c. begin ( ) ) ;
rep ( i, 0 , SZ ( c) ) c[ i] = ( mod- c[ i] ) % mod;
return solve ( n, c, VI ( a. begin ( ) , a. begin ( ) + SZ ( c) ) ) ;
}
} ;
int main ( )
{
while ( ~ scanf ( "%lld" , & n) )
{
VI vi;
vi. push_back ( 4 ) ;
vi. push_back ( 12 ) ;
vi. push_back ( 33 ) ;
vi. push_back ( 88 ) ;
vi. push_back ( 232 ) ;
vi. push_back ( 609 ) ;
printf ( "%lld\n" , linear_seq: : gao ( vi, n- 1 ) % mod) ;
}
}