Uva 11076 Add Again (数论+组合数学)

时间:2023-03-09 09:15:09
Uva 11076 Add Again (数论+组合数学)

题意:给你N个数,求把他们的全排列加和为多少

思路:对于这道题,假设数字k1在第一位,然后求出剩下N-1位的排列数num1,我们就可以知道k1在第一位时

排列有多少种为kind1, 同理,假设数字k2在第一位然后求出剩下N-1位的排列数num2,

我们就可以知道k2在第一位时的排列有多少种为kind2,

k1*num1+k1*num2.....+kn*numn 就是我们要求的这些数对第一位的所有贡献,

我们知道第一位的贡献=对第二位的贡献=第三位的贡献.....

把所有贡献加和,就能求出结果

知识:

1、 如何求重复数的全排列

元素表述:   a1,a1,...a1,   a2,a2,...a2,.......,an,an,...an 
         其中,a1的个数为N1,   a2的个数为N2,以此类推,总个数为M。

则可以证明不重复的排列种类的数目:   M!/(N1!*N2!*...*Nn!)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ull unsigned long long
using namespace std; ull C[][]; void get_C()
{
memset(C,,sizeof(C));
C[][]=;
C[][]=;
for(int i=;i<=;i++)
{
for(int j=;j<=i;j++)
{
C[i][j]=C[i-][j]+C[i-][j-];
}
}
} int main()
{
int n;
int data[];
int num[];
get_C();
while(cin>>n&&n)
{
memset(num,,sizeof(num));
for(int i=;i<n;i++)
{
cin>>data[i];
num[data[i]]++;
}
ull ans=;
for(int i=;i<=;i++)
{
ull k=;
if(num[i])
{
k=;
int m=n-;
num[i]--;
for(int j=;j<=;j++)
{
if(num[j]==) continue;
k=k*C[m][num[j]];
m=m-num[j];
//cout<<k<<endl;
}
num[i]++; }
ans=ans+i*k;
}
ull sum=;
for(int i=;i<n;i++)
sum=sum*+ans;
cout<<sum<<endl;
}
return ;
}