题意:
m个for循环嵌套,有两种形式,第一类从1开始到n,第二类从上一层循环当前数开始到n,第一层一定是第一种类型,求总的循环的次数对364875103取余的结果。
思路:
首先可以看出,每一个第一类循环都是一个新的开始,与前面的状态无关,所以可以把m个嵌套分为几个不同的部分,每一个部分由第一类循环开始,最终结果相乘即可。
剩下的就是第二类循环的问题,
假设一个m层循环,最大到n,分析一下得到如下结果:
定义在 t 层循环到 i 的次数为 ft(i) 次
- 对于第一层循环,循环到
i
,显然有
f1(i)=1总的循环次数是:∑f1(i)=n=C1n
- 对于第二层循环,因为第二层循环属于第二种循环,想要循环到
i
,那么相应的第一层循环就要
≤i
,也就是
f2(i)=∑j≤if1(j)=i总的循环次数是:∑f2(i)=(n+1)∗n2=C2n+1
- 对于第三层循环,同理可得:
f3(i)=∑j≤if2(i)=(i+1)∗i2总的循环次数是:∑f3(i)=∑12∗(i2+i)=(n+2)∗(n+1)∗(n)6=C3n+2
- …
- 可以发现对于第
k
层循环总的循环次数是
Ckn+k−1
接着我们需要计算
Ckn+k−1 %364875103的值
.比较坑爹的是
364875103
不是一个素数!但是对
364875103
进行素数检查时可以发现
364875103=97∗3761599,
而这两个因子都是素数,令
mod1=97,mod2=3761599,mod=364875103
令
m=k,n=n+k−1
,我们
把Cmn % mod的值记为x,把Cmn % mod1的值记为x1,把Cmn % mod2的值记为x2
则有:
x≡ x1(% mod1)x≡ x2(% mod2)
因为 mod1,mod2 都是素数,所以 x1和x2 都可以用 Lucas定理求解出来。 那么剩下的问题就是求解上面的 同余方程 了。
利用 中国剩余定理 求解同余方程。
我们定义:
inv1为:(mod2在模mod1域下的逆元)∗mod2inv2为:(mod1在模mod2域下的逆元)∗mod1
那么答案就是:
x=(inv1∗x1 +inv2∗x2)% mod
最后在根据乘法原理易知每段求得的答案需要累乘。
代码:
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using namespace std;
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define rep(i,k,n) for(int i=k;i<=n;i++)
template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
const int N=25;
const int mod1=97;
const int mod2=3761599;
const int mod=mod1*mod2;
int n,m,k;
int a[N];
ll fac1[mod1+10],fac2[mod2+10];
ll inv1,inv2;
ll pow_mod(ll x, ll n, ll p){
ll res=1;
while(n>0){
if(n&1)res=res*x%p;
x=x*x%p;
n>>=1;
}
return res;
}
ll C(ll n,ll m,ll p,ll fac[]){
if(m>n) return 0;
return fac[n]*pow_mod(fac[m]*fac[n-m]%p, p-2, p)%p;
}
ll lucas(ll n,ll m,ll p,ll fac[]){
if(m==0) return 1;
return ( C(n%p, m%p, p, fac)*lucas(n/p, m/p, p, fac) )%p;
}
void init(){
fac1[0]=1;fac2[0]=1;
for(int i=1; i<mod1; i++)
fac1[i]=(fac1[i-1]*i)%mod1;
for(int i=1; i<mod2; i++)
fac2[i]=(fac2[i-1]*i)%mod2;
inv1=mod2*pow_mod(mod2, mod1-2, mod1);
inv2=mod1*pow_mod(mod1, mod2-2, mod2);
}
int main(){
init();
int t,kase=1;read(t);
while(t--){
read(n),read(m),read(k);
rep(i, 0, k-1)read(a[i]);
a[k]=m;
ll ans=1;
rep(i, 0, k-1){
ll m1=lucas(a[i+1]-a[i]+n-1, a[i+1]-a[i], mod1, fac1);
ll m2=lucas(a[i+1]-a[i]+n-1, a[i+1]-a[i], mod2, fac2);
ll mm=(m1*inv1+m2*inv2) % mod;
ans=ans*mm % mod;
}
printf("Case #%d: %I64d\n", kase++, ans);
}
return 0;
}