HDU 4373 Mysterious For(Lucas 定理 + 中国剩余定理)

来源:互联网 发布:重庆时尚频道网络直播 编辑:程序博客网 时间:2024/04/28 20:22

HDU 4373(Lucas 定理 + 中国剩余定理)

题意:

一段程序共有m个for循环嵌套,有两种形式,第一类从1开始到n,第二类初始值为上一层当前值,累计到n,第一层一定是第一种类型,求总的循环的次数对364875103取余的结果。

思路:

fuck the 364875103!!!TMD居然是个合数!

一开始觉得顺序对结果没啥影响,yy出答案为nk1Cmk+1m+nk,并且很不幸地样例都过了,于是怒吃一发WA。

后来发现还是有一定影响的,每一个第一类循环都会截断当前状态,所以我们把m层循环分为k个部分,每个部分的起始都是第一类循环,每个部分长度为 len ,循环次数等于 Clenn+len1,最后把这k个次数乘起来即可。

由于mod是个合数,所以求组合数取余要用到lucas+CRT。

代码:

/* * @author FreeWifi_novicer * language : C++/C */#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<string>#include<map>#include<set>#include<vector>#include<queue>using namespace std;#define clr( x , y ) memset(x,y,sizeof(x))#define cls( x ) memset(x,0,sizeof(x))#define pr( x ) cout << #x << " = " << x << endl #define pri( x ) cout << #x << " = " << x << " " #define mp make_pair#define pb push_backtypedef long long lint;const lint p1 = 97 ;const lint p2 = 3761599 ;const lint MOD = p1 * p2 ;lint fac1[p1+5] , fac2[p2+5] ;int pos[18] ;lint inv1 , inv2 ;lint fast_pow( lint x , lint n , lint p ){    x %= p ;    lint res = 1 ;     while( n ){        if( n & 1 )            res = res * x % p ;        n >>= 1 ;        x = x * x % p ;    }    return res ;}void init(){    fac1[0] = fac2[0] = 1 ;    for( int i = 1 ; i <= p1 ; i++ )        fac1[i] =  fac1[i-1] * i % p1 ;    for( int i = 1 ; i <= p2 ; i++ )        fac2[i] =  fac2[i-1] * i % p2 ;    inv1 = p2 * fast_pow( p2 , p1 - 2 , p1 ) ;    inv2 = p1 * fast_pow( p1 , p2 - 2 , p2 ) ;}lint C( lint n , lint m , lint p , lint *fac){    if( n < m ) return 0 ;    return  fac[n] * fast_pow( fac[m] * fac[n-m] , p-2 , p ) % p ;}lint lucas( lint n , lint m , lint p , lint *fac ){    if( m == 0 ) return 1 ;    return C( n % p , m % p , p , fac ) * lucas( n / p , m / p , p , fac ) % p ;}int main(){    //freopen("input.txt","r",stdin);    int t ; cin >> t ; int kase = 1 ;    init() ;    while( t-- ){        lint n , m ;        int k ;        scanf( "%I64d%I64d%d" , &n , &m , &k ) ;        for( int i = 0 ; i < k ; i++ )            scanf( "%d" , &pos[i] ) ;         pos[k] = m ;        lint ans = 1 ;        for( int i = 0 ; i < k ; i++ ){            int len = pos[i+1] - pos[i] ;            lint tmp1 = lucas( n + len - 1 , len , p1 , fac1 )  ;            lint tmp2 = lucas( n + len - 1 , len , p2 , fac2 )  ;            lint tmp = ( tmp1 * inv1 + tmp2 * inv2 ) % MOD ;            ans = ( ans * tmp ) % MOD ;        }        printf( "Case #%d: %I64d\n" , kase++ , ans ) ;    }    return 0;}
0 0
原创粉丝点击