康託展開

康託展開...第一遍看到這個名稱的時候我是一臉懵逼的...(康託?康熙幾世孫?)

其實它的主要作用就是壓縮判重量...

舉個簡單的栗子...我們要判斷的內容實質是9的全排列...

如果直接開數組就是[123456789..987654321](當然如果你倔強地要從0開始我也不攔着...)

一算8億多,炸內存...預計威力達到學校機房爛掉...

我知道熱愛世界和平並且希望有個好成績的你不會願意這樣子的...

仔細想想其中有很多是浪費掉的,比如198307177這種有重複數字的,不可能出現...

所以康託展開就橫空出世了...

公式是這個樣子...

X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!

它求得的實際上是某個排列數的編號...

比如123456789對應的是0123456798對應的是1987654321對應的是362879...

這樣的話就剩下9!=362880種,存儲空間還可以留一部分給你住...(開玩笑...)

具體原理跟那個NOIP2014普及第四題的火星人中“求下一個排列數”類似...

康託展開就是把那一題倒了一下,從求第n個排列數變成了求某個排列數是第幾個...

上文引用自洛谷一篇題解P2578
公式:

x=i=1n(aibi1)×(ni)!

給出代碼:

#include<cstdio>
#include<iostream>
#define N 10
using namespace std;
int a[N],n,c[N];
bool b[N];
int Contor(int x){
    int num=0,cnt,ans=0;
    while(x!=0){
        a[++num]=x%10;
        x/=10;
    }
    for(int i=num;i>=1;i--){
        cnt=0;
        for(int j=num;j>=i+1;j--)if(a[j]<a[i])cnt++;
        ans+=(a[i]-cnt-1)*c[i-1];
    }
    return ans;
}
void dfs(int x,int y){
    if(x==n+1){
        printf("%d %d\n",y,Contor(y));
        return;
    }
    for(int i=1;i<=n;i++){
        if(!b[i]){
            b[i]=1;
            dfs(x+1,y*10+i);
            b[i]=0;
        }
    }
}
int main(){
    c[0]=1;
    for(int i=1;i<=9;i++)c[i]=c[i-1]*i;
    scanf("%d",&n);
    dfs(1,0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章