POJ 2992

此题A得艰难,应该是有很多组数据吧,使得容易超时。

直接求出组合数是不可能的,因而,只能把各个数都计算其各素因子个数,再计算即可。

而直接计算,必定是要超时的,所以,只好先预处理所有结果,再输出了。

首先筛选素数,分解0~440的素因子。

然后,Cnk=(n*(n-1)*(n-2)*...(n-k+1))/k!,计算,按各数所拆解素因子计算出组合数的素因子及其个数,再求出即可。

而对于Cn(k+1)=(n*(n-1)*(n-2)*...(n-k+1)*(n-k))/(k+1)!只需在Cnk的基础上递推过来,亦即再加上n-k的素因子个数减去k+1素因子个,否则,TLE

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

bool isprime[500];
int prime[500],np;
int cnum[500][500];
__int64 Cnk[500][500];

void prim(){
	int Max=500;
	memset(isprime,true,sizeof(isprime));
	memset(cnum,0,sizeof(cnum));
	np=0;
	int i,j;
	isprime[1]=false;
	for(i=2;i<Max;i++){
		if(isprime[i]){
			prime[np++]=i;
			for(j=i*i;j<Max;j+=i)
			isprime[j]=false;
		}
	}
	
	memset(cnum,0,sizeof(cnum));
	for(int i=440;i>=0;i--){
		int tmp=i;
		for(int j=0;prime[j]<=tmp;j++){
			if(tmp%prime[j]==0){
				while(tmp%prime[j]==0){
					cnum[i][j]++;
					tmp/=prime[j];
				}
			}
		}
	}
	
}

void divide(){
	int ans[500];
	for(int n=0;n<=440;n++){
		for(int k=0;k<=n;k++){
			Cnk[n][k]=1;
			if(k==0){ continue; }
			if(k==1){
				for(int i=0;i<np;i++){
					ans[i]=cnum[n][i];
				}
			}
			else{
				for(int i=0;i<np;i++){
					ans[i]=ans[i]+cnum[n-k+1][i]-cnum[k][i];
				}
			}
			for(int i=0;i<np;i++)
			Cnk[n][k]*=(__int64)(ans[i]+1);
		}
	}
}

int main(){
	int n,k,tmp;
	prim();
	divide();
	while(scanf("%d%d",&n,&k)!=EOF){
		printf("%I64d\n",Cnk[n][k]);
	}
	return 0;
}

  

posted @ 2014-09-12 21:24  chenjunjie1994  阅读(247)  评论(0编辑  收藏  举报