【HDU】4869 Turn the pokers 组合数

传送门:【HDU】4869 Turn the pokers


题目分析:每次写和组合数有关的题目都要纠结半天= =||。

由于每次翻转的张数x是确定的,那么每次翻转的奇偶性也是确定的。如果x为奇数,则这次翻转后1的个数的增量一定是奇数(增量可以是负数);同理x为偶数,则这次翻转后1的个数的增量一定是偶数。并且如果x的和为奇数,则最后的正面朝上的1的个数也是奇数个,和为偶数同理。

如果我们得到了最后一次翻转后能达到的最小的正面朝上的1的个数以及最大的个数,那么易得L,L+2,L+4,...,R-2,R,一定都是可以达到的(可以理解为既然能达到那么大(那么小),那么我总可以使它不那么大(那么小)),而且L,R一定是同奇偶的。

那么最大的L和最小的R通过递推可以计算出来,之后就是计算组合数了(x个1随意摆放的种数)。由于本题的数据符合费马小定理,那么可以用费马小定理将组合数中的除法转化成乘法。

假设用C(n,m)表示从n个位置选择m个放1的方案数。那么C(n,m) = n!/(m!*(n-m)!),设(m!*(n-m)!) = a,由费马小定理可知:a^(p-2) = (1/a)%p。所以将除法转化为乘法以后套套快速幂即可。


代码如下:


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

#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define REV( i , a , b ) for ( int i = a - 1 ; i >= b ; -- i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )

#define CLR( a , x ) memset ( a , x , sizeof a )

typedef long long LL ;

const int mod = 1e9 + 9 ;
const int MAXN = 100005 ;

LL f[MAXN] ;
int n , m ;

void fun () {
	f[0] = 1 ;
	REP ( i , 1 , MAXN )
		f[i] = ( f[i - 1] * i ) % mod ;
}

LL pow ( LL a , int b ) {
	LL res = 1 , tmp = a ;
	while ( b ) {
		if ( b & 1 )
			res = res * tmp % mod ;
		tmp = tmp * tmp % mod ;
		b >>= 1 ;
	}
	return res ;
}

void solve () {
	int L = 0 , R = 0 ;
	int l , r , x ;
	REP ( i , 0 , n ) {
		scanf ( "%d" , &x ) ;
		if ( x <= L )
			l = L - x ;
		else if ( x <= R )
			l = ( L ^ x ) & 1 ;
		else
			l = x - R ;
		if ( x + R <= m )
			r = x + R ;
		else if ( x + L <= m )
			r = m - ( ( ( L + x ) ^ m ) & 1 ) ;
		else
			r = m - ( x + L - m ) ;
		L = l , R = r ;
	}
	LL ans = 0 ;
	for ( int i = L ; i <= R ; i += 2 )
		ans = ( ans + ( f[m] % mod ) * pow ( f[i] * f[m - i] % mod , mod - 2 ) % mod ) % mod ;
	printf ( "%I64d\n" , ans ) ;
}

int main () {
	fun () ;
	while ( ~scanf ( "%d%d" , &n , &m ) )
		solve () ;
	return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值