康託展開...第一遍看到這個名稱的時候我是一臉懵逼的...(康託?康熙幾世孫?)
其實它的主要作用就是壓縮判重量...
舉個簡單的栗子...我們要判斷的內容實質是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對應的是0,123456798對應的是1,987654321對應的是362879...
這樣的話就剩下9!=362880種,存儲空間還可以留一部分給你住...(開玩笑...)
具體原理跟那個NOIP2014普及第四題的火星人中“求下一個排列數”類似...
康託展開就是把那一題倒了一下,從求第n個排列數變成了求某個排列數是第幾個...
上文引用自洛谷一篇題解P2578
公式:
給出代碼:
#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);
}