康托展開(樹狀陣列逆序對優化)

2022-07-23 20:48:23 字數 1939 閱讀 2574

康托展開是乙個全排列到乙個自然數的雙射。設有n個數(1,2,3,4,…,n),可以有組成不同(n!種)的排列組合,康托展開表示的就是是當前排列組合在n個不同元素的全排列中的名次。

\(x = a[n] * (n - 1)! + a[n - 1] * (n - 2)! + a[n - 2] * (n - 3)! …… + a[2] * 1! + a[1] * 0!\)

例如3的全排列

估計大家應該不用解釋都應該明白了,這裡的a[i]係數是如何來的了

3 > 2, 3 > 1,得到a[3] = 2,2 > 1,得到a[2] = 1

其中的康托展開的數值代表的是當前項在全排類中的數值下標(注意下標從0開始計數)

/*

康托展開計算o(n * n)

未優化,明天把優化的**補上。

*/#includeusing namespace std;

int fac[10] = ;//階乘

int cantor(int a, int n)

return s;

}int main() , n = 5;

printf("%d\n", cantor(a, n));

return 0;

}

94
也就是康托展開的逆過程,就拿上面的例子來說

排列4 5 3 1 2的康托展開值是94。

/*

逆康托展開計算o(n * n)

康托展開項未優化

*/#includeusing namespace std;

int fac[10] = ;//階乘

int ans[10];

int cantor(int a, int n)

return s;

}void decantor(int s, int n)

}int main() , n = 5;

printf("%d\n", cantor(a, n));

decantor(cantor(a, n), n);

for(int i = 0; i < n; i++)

printf("%d%c", ans[i], i + 1 == n ? '\n' : ' ');

return 0;

}

本來寫了乙個線段樹的,發現好長啊,就沒抄上來,改成了樹狀陣列。當然了資料量小,離散化自然也就可以不用了。

一開始想成了,可以用並查集維護逆康托展開,發現錯了,,,想了半天也沒想出能用什麼比較簡潔的資料結構來實現o(n)的逆康托展開。

這個 \(o(n^n)\) 的vector成本確實有點高了。

/*

*/#includeusing namespace std;

const int n = 15;

int fac[n] = , ans[n], tree[n], sum, n;

inline int lowbit(int x)

void add(int pos)

}int query(int pos)

return sum;

}int cantor(int a, int n)

return s;

}void decantor(int s, int n)

}int main()

// int a[10] = ;

// do while(next_permutation(a, a + n));

return 0;

}

對康託展開的一些心得

康托展開 對於全排列中形成的乙個陣列,可以知道他是排列中的第幾種.具體公式為 x an n 1 an 1 n 2 ai i 1 a2 1 a1 0 其中,a為整數陣列,並且0 ai一下是一些 比如表示1,2,3,n的排列如 按從小到大排列一共6個。123 132 213 231 312 321 代表...

樹狀陣列求逆序對

題目描述 給定乙個陣列a,它包含n個整數,分別是a 1 a 2 a n 如果存在下標i和j,使得 i j 且 a i a j 同時成立,則 i,j 就為乙個 逆序對 那麼a陣列總共有多少對不同的 逆序對 輸入格式 1247.in 第一行為n 1 n 100000 接下來是n行,每行乙個長整型範圍內的...

樹狀陣列求逆序對

很久以前就學了樹狀陣列,也知道可以用來求逆序對,然而一直沒弄明白他是怎麼實現的 可能當時沒搞清楚逆序對是什麼吧。逆序對就是如果i j a i a j 這兩個就算一對逆序對,簡單來說,所有逆序對的個數和就是找每乙個數的前面有幾個比他的大的數,他們加起來的和就是逆序對的總數。知道什麼是逆序對後就好辦了,...