1. 程式人生 > >UVA 11076(數論 不全相異元素全排列)

UVA 11076(數論 不全相異元素全排列)

題目連結:https://cn.vjudge.net/contest/269773?tdsourcetag=s_pcqq_aiomsg#problem/G

題意:給你N個數,求把他們的全排列加和為多少

參考https://www.cnblogs.com/hbutACMER/p/4235696.html

考慮任意一位i,假設我們在i位放置x,則對應(n−1)!/(d0!∗d1!∗...∗dx!∗...∗d9!)(n−1)!/(d0!∗d1!∗...∗dx!∗...∗d9!)種情況。

PS:前導0也算一種情況,舉個栗子 

3

0 0 1

答案是1 1 1

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define limit(a,b) memset(a,b,sizeof a)
const int N=5e5+7;
const int INF = 0x3f3f3f3f;
const int mod=1e6;
ull f[20];
int b[N],a[N];
// 如何求重複數的全排列
//         元素表述:   a1,a1,...a1,   a2,a2,...a2,.......,an,an,...an
//         其中,a1的個數為N1,   a2的個數為N2,以此類推,總個數為M。
//
//         則可以證明不重複的排列種類的數目:   M!/(N1!*N2!*...*Nn!)
//然後這道題就可以轉化成在任意一位i上當前值是a的組合數的情況為s,那麼
//當前位所得的值為a*s,其餘的數字情況一樣處理
int main()
{
    int n;
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    f[0]=1;
    rep(i,1,12) f[i]=i*f[i-1];
    while(scanf("%d",&n)!=EOF,n){
            limit(b,0);
            int cnt=0;//
        rep(i,1,n) {int t;
        scanf("%d",&t);
        b[t]++;
        if(b[t]==1) a[cnt++]=t;
        }
        ull ans=0;
        ull temp;
        rep(i,0,cnt-1){//因為每一位的情況是相同的,可以通過模擬發現,因此只需要求一位的情況就好
           temp=f[b[a[i]]-1];     //其他位那就相加移位就好。
            rep(j,0,cnt-1){
            if(i==j) continue;
            temp*=f[b[a[j]]];
            }
            ans+=(f[n-1]/temp)*a[i];
            }
            temp=ans;//每一位的總和
            ans=0;
        rep(i,0,n-1) ans+=temp,temp*=10;
        printf("%lld\n",ans);
        }
     return 0;
}