HDU 4373 Mysterious For [组合数学]
定义两类循环,第一类就是最简单的for(int i=0;i<n;i++)....第二类就是类似与for(int i=0;i<n;i++)for(int j=i;j<n;j++)for(int k=j;k<n;k++)..一共有M<100000个循环,其中一类不超过15个,求最内层循环内的语句执行的次数。
对每一段连续的二类循环,可以想到就是求从N个数里选出M个数组成一个序列,这个序列满足不降性质,求这样的序列有多少个。
理解为插板,M个数N-1个板,在Ai和Ai-1数之间插x个板代表Ai-Ai-1=x。所以答案就是C(M+N-1,N-1)。
组合数比较大,因为给的MOD不是质数,我是暴力统计每个素因子有多少个的。。据说LUCAS加中国剩余定理也可以搞,数论太菜搞不来。。。
1 #include <string.h> 2 #include <stdio.h> 3 #define MAXN 1200005 4 #define mod 364875103 5 typedef long long LL; 6 int notpri[MAXN], pri[MAXN], pris; 7 int cas, n, m, k, ans, kk[20]; 8 int tot[MAXN], nn, mm, nm; 9 void init(){ 10 for (int i = 2; i < MAXN; i++) if(!notpri[i]) 11 for (int j = i*2; j < MAXN; j+=i) notpri[j] = 1; 12 for (int i = 2; i < MAXN; i++) if(!notpri[i]) pri[pris++] = i; 13 } 14 LL powmod(int x,int d){ 15 LL ans = 1, tmp = x; 16 for (; d; d >>= 1, tmp = tmp * tmp % mod) 17 if (d&1) ans = ans * tmp % mod; 18 return ans; 19 } 20 LL c(int n,int m) { 21 for (int i = 0; pri[i] <= n; i++) { 22 nn = n, mm = m, nm = n - m, tot[i] = 0; 23 while (nn) nn /= pri[i], tot[i] += nn; 24 while (mm) mm /= pri[i], tot[i] -= mm; 25 while (nm) nm /= pri[i], tot[i] -= nm; 26 } 27 LL ans = 1; 28 for (int i = 0; pri[i] <= n; i++) 29 ans = ans * powmod(pri[i], tot[i]) % mod; 30 return ans; 31 } 32 int main(){ 33 //freopen("test.in","r",stdin); 34 init(); 35 scanf("%d", &cas); 36 for (int ca = 1; ca <= cas; ca++) { 37 scanf("%d%d%d", &n, &m, &k); 38 for (int i = 0; i < k; i++) scanf("%d", &kk[i]); kk[k] = m; 39 ans = 1; 40 for (int i = 1; i <= k; i++) 41 ans = ans * c(n+kk[i]-kk[i-1]-1, n-1) % mod; 42 printf("Case #%d: %I64d\n", ca, ans); 43 } 44 return 0; 45 }