NYOJ 743

复杂度

描述

for(i=1;i<=n;i++)

  for(j=i+1;j<=n;j++)

    for(k=j+1;k<=n;k++)

        operation;

你知道 operation 共执行了多少次吗;

输入
输入 m 和n 表示m为for循环的层数,n为for中的n。
(n,m<=2000),输入以n==0和m==0结束
输出
输出operation执行的次数(输入结果mod 1009)
样例输入
2 3
1 3
2 4
0 0
样例输出
3
3
6

  仔细观察就会发现,这里面的 i, j, k,... 等等,他们的开头处的取值完全不一样,这就好比有n个数值,开头取一个,有n中取法;再取第二个,有n-1中取法;再取第三个,有n-2种取法;。。。一直到再取第m个有n-m+1中取法。这么一说,想到了什么?组合数!有木有!!!就是这么神奇,其实整个题目就是要计算组合数的一个题。

     接着就是组合数公式的编程,而常识告诉我们,一旦计算C(2000,1000)这种情况,用阶层计算是十分恐怖的,辛好结果是要求对1009取余的结果,那么问题来了,如何不用阶层来快速计算组合数。

首先我们回顾下组合数的公式:

  

以及组合数的一些性质:

C(n,m)=  C(n-1,m-1)+C(n-1,m)  关于这个公式的证明,可以套用上面的公式来直接证明,还有直接逻辑思考套用到某个实际事例中就能证明,这里就不总结了。

C(n,m)= C(n,m-1) + C(n-1,m-1)  

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int N = 1009;
 6 int f[2005][2005] = {0};
 7 void fun()
 8 {
 9     for(int i = 1; i <= 2000; i++)
10         for(int j = i; j <= 2000; j++)
11         {
12             if(i == j)
13             {
14                 f[i][j] = 1;
15                 continue;
16             }
17             if(i == 1)
18             {
19                 f[i][j] = j%N;
20                 continue;
21             }
22             f[i][j] = ((f[i][j-1]) + (f[i-1][j-1]))%N;
23         }
24 }
25 int main()
26 {
27     fun();
28     int n,m;
29     while(scanf("%d%d",&m,&n),n+m)
30     {
31         printf("%d\n",f[m][n]);
32     }
33     return 0;
34 }

 

其实这是一个很普遍的问题,就是组合数取模问题,这下就一次性解决了吧。

http://blog.csdn.net/acdreamers/article/details/8037918

http://www.3773.com.cn/NCRE/434536.shtml

 

posted on 2016-04-16 20:56  逸阳  阅读(147)  评论(0编辑  收藏  举报

导航