HDOJ1261排列组合+大数乘除

http://acm.hdu.edu.cn/showproblem.php?pid=1261

 

题解

  1. 令sum=a1+a2+···+an
  2. 种数为 sum!/(a1!a2!···an!)
  3. 其中sum最大为25*12,而int能容纳的最大阶乘为12,long long能容纳的最大阶乘不超过50,故这是一个大数乘法的问题https://blog.csdn.net/wang_1997/article/details/68241892
    /a*b=res
    //a,res均从前往后为个,十,百... 
    void multiply(vector<long long> a,long long b,vector<long long>& res,int& k)
    {
    	int p=0;
    	int cnt=k;
    	vector<long long> tmp(5000,0);
    	while(b)
    	{
    		int digit=b%10;
    		for(int i=0;i<k;i++) 
    		{
    			tmp[p+i]+=digit*a[i];
    			if(p+i+1>cnt)
    				cnt=p+i+1;
    		}
    		p++;
    		b/=10;
    	}
    	
    	
    	k=cnt;
    	for(int i=0;i<k;i++)
    	{
    		tmp[i+1]+=tmp[i]/10;
    		tmp[i]=tmp[i]%10;
    	}
    	while(tmp[k])
    	{
    		tmp[k+1]+=tmp[k]/10;
    		tmp[k]=tmp[k]%10;
    		k++;
    	}
    	res=tmp;
    }
  4. 由于sum!可能为大数,故又涉及到大数除法的问题。https://blog.csdn.net/z_y1314/article/details/79716387
    void divide(vector<long long> a,long long b,vector<long long>& res,int& k)
    {
    	vector<long long> tmp(5000,0);
    	long long rest=0;
    	int ind=0;
    	for(int i=0;i<k;i++)
    	{
    		rest=rest*10+a[i];
    		if(ind||rest>=b)
    		{
    			tmp[ind++]=rest/b;
    			rest=rest%b;
    		}
    	}
    	res=tmp;
    	k=ind;
    }

AC代码

#include<iostream>
using namespace std;
#include<algorithm>
#include<vector>
#define N 250

vector<long long> jc(13);

void init()
{
	jc[0]=1;
	jc[1]=1;
	for(int i=2;i<13;i++)
		jc[i]=jc[i-1]*i;
}

/a*b=res
//a,res均从前往后为个,十,百... 
void multiply(vector<long long> a,long long b,vector<long long>& res,int& k)
{
	int p=0;
	int cnt=k;
	vector<long long> tmp(5000,0);
	while(b)
	{
		int digit=b%10;
		for(int i=0;i<k;i++) 
		{
			tmp[p+i]+=digit*a[i];
			if(p+i+1>cnt)
				cnt=p+i+1;
		}
		p++;
		b/=10;
	}
	
	
	k=cnt;
	for(int i=0;i<k;i++)
	{
		tmp[i+1]+=tmp[i]/10;
		tmp[i]=tmp[i]%10;
	}
	while(tmp[k])
	{
		tmp[k+1]+=tmp[k]/10;
		tmp[k]=tmp[k]%10;
		k++;
	}
	res=tmp;
}



void divide(vector<long long> a,long long b,vector<long long>& res,int& k)
{
	vector<long long> tmp(5000,0);
	long long rest=0;
	int ind=0;
	for(int i=0;i<k;i++)
	{
		rest=rest*10+a[i];
		if(ind||rest>=b)
		{
			tmp[ind++]=rest/b;
			rest=rest%b;
		}
	}
	res=tmp;
	k=ind;
}



int main()
{
	int n;
	init();
	while(cin>>n&&n)
	{
		vector<int> a(n);
		int sum=0;
		for(int i=0;i<n;i++)
		{
			cin>>a[i];
			sum+=a[i];	
		}
		vector<long long> up(5000,0);
		int k=0;
		if(sum<=12)
		{
			long long tmp=jc[sum];
			for(int i=0;i<n;i++)
				tmp/=jc[a[i]];
			cout<<tmp<<endl;
			continue;
		}
		else
		{
			long long tmp=jc[12];
			while(tmp)
			{
				up[k++]=tmp%10;
				tmp/=10;	
			}
			for(int i=13;i<=sum;i++)
			{
				multiply(up,i,up,k);
			}
			reverse(up.begin(),up.begin()+k);
			for(int i=0;i<n;i++)
			{
				divide(up,jc[a[i]],up,k);
			}
			for(int i=0;i<k;i++)
			{
				cout<<up[i];
			}
			cout<<endl;
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值