HDU 4373(Lucas 定理 + 中国剩余定理)
题意:
一段程序共有m个for循环嵌套,有两种形式,第一类从1开始到n,第二类初始值为上一层当前值,累计到n,第一层一定是第一种类型,求总的循环的次数对364875103取余的结果。
思路:
fuck the 364875103!!!TMD居然是个合数!
一开始觉得顺序对结果没啥影响,yy出答案为 nk−1∗Cm−k+1m+n−k ,并且很不幸地样例都过了,于是怒吃一发WA。
后来发现还是有一定影响的,每一个第一类循环都会截断当前状态,所以我们把m层循环分为k个部分,每个部分的起始都是第一类循环,每个部分长度为 len ,循环次数等于 Clenn+len−1 ,最后把这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_back
typedef 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;
}