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 }
posted @ 2012-10-10 10:16  Burn_E  阅读(349)  评论(0编辑  收藏  举报