HDU4390Number Sequence(容斥原理)

bigbigship發表於2015-03-23

題目連結:

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


題意:

有一個長度為n的序列,b1,b2,b3,,,,,bn;

尋找一個長度也為n的序列 使得滿足以下條件

1) a1*a2*...*an=b1*b2*...*bn;

2)ai>1;


分析:

很明顯就是把bi的所有素因子統計以下,然後重新組合分成n份。

我們先回顧以下一個子問題。

把m個相同的球分到n個不相同的容器裡,每個容器能為空。

擋板法:

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

然後我們就來了思路了 因為ai大於1,說明不能為空。我們可以從反面

來考慮,先求出一共所有的方案數num1,然後再通過容斥原理來求出,至少

存在一個為空的方案數num2。

ans = num1 - num2.


程式碼如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

const int maxn=1005;
const int MOD=1000000007;
int p[maxn];
int a[maxn];
LL c[maxn][maxn];

void init(){
	int i,j;
	for(i=0;i<maxn;i++){
		c[i][i]=c[i][0]=1;
		for(j=1;j<i;j++)
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
	}
}

int getnum(int m,int n){
	return c[m+n-1][n-1];
}

LL solve(int cnt,int n){
	int i,j;
	LL ans=1;
	for(i=0;i<=cnt;i++)
		ans=(ans*getnum(a[i],n))%MOD;
	for(i=1;i<n;i++)
	{
		LL tmp=c[n][i];
		for(j=0;j<=cnt;j++)
			tmp=(tmp*getnum(a[j],n-i))%MOD;
		if(i&1)
			ans=((ans-tmp)%MOD+MOD)%MOD;
		else
			ans=(ans+tmp)%MOD;
	}
	return ans;
}

int main()
{
	init();
	int n;
	while(~scanf("%d",&n))
	{
		int t,i,j;
		int cnt=0;
		for(i=0;i<n;i++){
			scanf("%d",&t);
			for(j=2;j*j<=t;j++){
				while(t%j==0){
					p[cnt++]=j;
					t/=j;
				}
			}
			if(t>1)
				p[cnt++]=t;
		}
		sort(p,p+cnt);
		a[0]=1;
		i=0;
		for(j=1;j<cnt;j++){
			if(p[j]==p[j-1])
				a[i]++;
			else
				a[++i]=1;
		}
		cnt=i;
		printf("%I64d\n",solve(cnt,n));
	}
	return 0;
}




相關文章