Divisors
Description
Your task in this problem is to determine the number of divisors of
Cnk. Just for fun -- or do you need any special reason for such a useful computation?
Input
The input consists of several instances. Each instance consists of a single line containing two integers n and k (0 ≤ k ≤ n ≤ 431), separated by a single space.
Output
For each instance, output a line containing exactly one integer -- the number of distinct divisors of
Cnk. For the input instances,
this number does not exceed 263 - 1.
Sample Input 5 1 6 3 10 4 Sample Output 2 6 16 Source
CTU Open 2005
|
算法分析: 数论中一个最简单的定理 要注意的是所有的树都可以分解成多个质数相乘的形式 例如 36可以分解成2*2*3*3 底数2的指数是2 底数3的指数是2,这样根据组合数学的原理 可以求出这个数所有的除数的个数 除数的个数=(各个位上指数+1)相乘 例如 324=2*2*3*3*3*3 就有两位,底数为2的指数为2 底数为3的指数为4 那么 324的除数有=(2+1)*(3+1)。
还要注意的是此题的数据量比较庞大,直接对每个数进行分解所占用的时间大,容易tle,要存储阶乘的质因数分解的结果能有效的提高运算的速度。
还要注意题目中 中标红的话 输出的结果会超过int的值
要注意的是 最好采用记忆化存储的方式 不用每次都对其进行分解,减少时间。
post code:
#include<stdio.h> #include<string.h> int used[432]; int a[432][84]; //将阶乘按质因数分解的结果存储。 int c[84]; int d[84]; int main() { int i,j,len; memset( used, 0, sizeof(used) ); for( i=2; i*i<432; i++ ) //筛选法求质数 { if(used[i]==0)for(j=2*i; j<432; j+=i) used[j]=1; } j=1; for( i=2; i<432; i++ ) //将质数存放到c数组中 if(used[i]==0){ c[j]=i; j++; } len=j; int m,n,num,flag=0; memset( a, 0, sizeof(a) ); for( i=431; i>=2; i-- ) //对2-431进行质因数的分解 { num=i; for(j=1;j<84;j++) { while(num%c[j]==0) { a[i][j]++; num/=c[j]; } if(num==1)break; } } for( i=3; i<432; i++) //将分解后的质因数进行阶乘的累积 由单个数的分解编程阶乘的分解 { for( j=1; j<84; j++) { a[i][j]+=a[i-1][j]; } } __int64 sum=1; while( scanf("%d %d",&m,&n)!=EOF ) { memset(d,0,sizeof(d)); for(i=1;i<len;i++) { d[i]=a[m][i]-a[m-n][i]-a[n][i]; //有点类似树状数组的求值 直接调用Cnk的分解形式 } sum=1; for(i=1; i<len; i++) { if(d[i]!=0){ sum*=d[i]+1; //求出最终结果 } } printf("%I64d\n",sum); } }