Loading

题($preblem$)

基本是卡特兰数的一道题,加深了我对卡特兰数的印象。

在坐标轴上走最好类比成进栈出栈问题,往前走等于进栈一个数,往后走就是出栈一个数。
求有多少种出栈序列。\(Catlan\)学习
\(Catlan(n/2)\)\(typ==1\)就解决了

\(typ==0\)就是一个水组合式子

\[ans=\sum_{2|i}^nC(i,i/2)*C(n-i,(n-i)/2)*C(n,i) \]

代表的意义从\(n\)步中找出来\(i\)步上下走,\(n-i\)步左右走。
为什么不用排列?
因为操作没有什么不同,都是往右或上走一步,没有什么可以排的

\(typ==2\),另\(f[i]\)为走\(i\)步回到原点时的方案数

\[f[i]=\sum_{2|j}^if[i-j]*4Catlan(j/2-1) \]

先选择\(i-j\)步让他回到原点,然后有四个方向做一遍进出栈问题就行了。
注意\(j/2\)要减一因为相当与栈底元素无法自由进出,跟没有没啥区别

\(typ==3\),直接选出来在两个方向走的步数一个\(Catlan\)就行了。

\[ans=\sum_{2|i}^nC(i,n)*Catlan(i/2)*Catlan((n-i)/2) \]

code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long
#define R register int
#define printf Ruusupuu = printf

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;
const int M = 1e9 + 7 ;

int Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m , k , f [N] , js [N] , inv [N] ;

inline int T( int a , int b ){ return 1ll * a * b % M ; } 
inline int J( int a , int b ){ return a + b >= M ? ( a + b - M ) : a + b ; }
inline int S( int a , int b ){ return a - b < 0 ? ( a - b + M ) : a - b ; }
inline int C( int a , int b ){ return T( js [a] , T( inv [b] , inv [a - b] ) ) ; }
inline int Cat( int x ){ return S( C( 2 * x , x ) , C( 2 * x , x - 1 ) ) ; }

void sc(){
	n = read() , k = read() ; js [0] = js [1] = inv [0] = inv [1] = 1 ;
	for( R i = 2 ; i < N ; i ++ ) js [i] = T( js [i - 1] , i ) , inv [i] = T ( ( M - M / i ) , inv [M % i] ) ;
	for( R i = 2 ; i < N ; i ++ ) inv [i] = T( inv [i] , inv [i - 1] ) ;
}

void work(){
	if( k == 0 ){
		int ans = 0 ;
		for( R i = 0 ; i <= n ; i += 2 )
			ans = J ( ans , T( T ( C ( n - i , ( n - i ) / 2 ) , C( i , i / 2 ) ) , C( n , i ) ) ) ;
		printf( "%ld\n" , ans ) ;  
	}
	if( k == 1 ){
		n /= 2 ;
		printf( "%ld\n" , Cat( n ) ) ;
	}
	if( k == 2 ){
		f [0] = 1 ; 
		for( R i = 2 ; i <= n ; i += 2 ){
			for( R j = 2 ; j <= i ; j += 2 ){
				//printf( "%ld\n" , i ) ;	
				f [i] = J( f [i] , T( f [i - j] , T( 4 , Cat( j / 2 - 1 ) ) ) ) ;
			} 
		} printf( "%ld\n" , f [n] ) ;
	}
	if( k == 3 ){
		int ans = 0 ;
		for( R i = 0 ; i <= n ; i += 2 ){
			ans = J ( ans , T( C( n , i ) , T ( Cat( i / 2 ) , Cat( ( n - i ) / 2 ) ) ) ) ;
		} printf( "%ld\n" , ans ) ;	   
	}
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}
posted @ 2021-06-09 06:57  Soresen  阅读(43)  评论(0)    收藏  举报