POJ 2992 Divisors

Divisors
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7635 Accepted: 2098

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 2 63 - 1.

Sample Input

5 1
6 3
10 4

Sample Output

2
6
16

Source

看似简单的一道题目,纠结了我好久好久。。Orz
我先开始太天真了,因为数据量只有431所以我以为随便搞
于是就直接把那个C(n,r)的每一个乘法分开来质因数分解。(其实对于单组数据还是很快的,不过数据量太大)
然后直接超时了。紧接着又各种优化,仍然超时。后来就直接预处理打表
我试了试,果然很慢,要把所有的表打出来,差不多要花5到6秒的时间
而且优化了和没优化差不多。。
然后后来又用到了那个C(n,r)=C(n,n-r)的公式继续优化,瞬间,时间降到了1秒多
但是速度仍然很慢,还是要TLE。
然后看了下discuss
发现有如下公式:
C(n,k+1)=C(n,k)/(k+1)*(n-k)
于是就想到了递推。可惜我模拟能力严重匮乏
写了很久终于搞出来了。
用这个方法,我没有任何优化,688MS过掉了
我的代码:
#include<stdio.h> #include<string.h> typedef __int64 ll; ll ans[500][500]; ll num[500]; void solve(ll n,ll flag) { ll i; for(i=2;i*i<=n;i++) { if(n%i==0) { n=n/i; num[i]=num[i]+flag; while(n%i==0) { num[i]=num[i]+flag; n=n/i; } } if(n==1) break; } if(n>1) num[n]=num[n]+flag; } ll C(ll n,ll r) { ll i,res=1; for(i=1;i<=r;i++) solve(n-i+1,1); for(i=1;i<=r;i++) solve(i,-1); for(i=0;i<500;i++) res=res*(num[i]+1); return res; } ll ADD(ll x,ll y) { ll res=1,i; solve(x,-1); solve(y,1); for(i=0;i<500;i++) res=res*(num[i]+1); return res; } void init() { ll i,j; ans[0][0]=1; ans[1][0]=1; ans[1][1]=1; for(i=2;i<432;i++) { memset(num,0,sizeof(num)); ans[i][0]=C(i,0); ans[i][i]=ans[i][0]; for(j=1;j<i;j++) ans[i][j]=ADD(j,i-j+1); } } int main() { int n,k; init(); while(scanf("%d%d",&n,&k)!=EOF) printf("%I64d\n",ans[n][k]); return 0; }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值