关于数论【康托展开及其逆运算】
生活随笔
收集整理的這篇文章主要介紹了
关于数论【康托展开及其逆运算】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
表示這個(gè)東西背了很多次,但是次次忘,希望這次能夠記住吧。
康托展開:
問45231是n=5的全排列中第幾個(gè)排列?
ans:= 3*4! + 3*3! + 1*2! + 1*1! + 0*0! =93
這時(shí)求出的是在45231前面全部的排列,排名還要加1
所以對此的做法,就是將階乘前面的求出來,這個(gè)就是在a[i]前面,還沒出現(xiàn)過的數(shù)字。比如4前面1~3都沒出現(xiàn)而1(或2或3)xxxx肯定在4xxxx前面,因?yàn)橛兴膫€(gè)不定的數(shù)字,所以乘上4!
逆運(yùn)算:
問n=5的全排列中第94個(gè)是誰?94先-1
94/4!=3.875
所以第一個(gè)數(shù)字前面有3個(gè)數(shù)字
94先減3*4!=22
22/3!=3.6666666666666666666666666666667
前面還是有三個(gè),因?yàn)?之前用過了,所以是5
由此類推。這個(gè)東西常用于狀態(tài)壓縮的。
模板題caioj1220:
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; int n,a[20]; LL jc[20]; bool bo[20]; void kangtuo1() {jc[0]=1;for(int i=1;i<=n;i++){scanf("%d",&a[i]);jc[i]=jc[i-1]*i;}LL ans=0;//有多少個(gè)這個(gè)全排列前面的 memset(bo,false,sizeof(bo));//這個(gè)有沒有在前面出現(xiàn)過for(int i=1;i<=n-1;i++){ int k=0;//k表示前面有多少個(gè)沒被訪問過的for(int j=1;j<a[i];j++)if(bo[j]==false)k++;bo[a[i]]=true;//當(dāng)前這個(gè)數(shù)被訪問過 ans+=k*jc[n-i];//乘以當(dāng)前個(gè)數(shù)的階乘 }printf("%lld\n",ans+1); } void kangtuo2() {LL ans;scanf("%lld",&ans);ans--; memset(bo,false,sizeof(bo)); for(int i=1;i<=n;i++){LL k=ans/jc[n-i];//有多少個(gè)比第i個(gè)位置小的數(shù) ans-=k*jc[n-i];for(int j=1;j<=n;j++)if(bo[j]==false){if(k==0){a[i]=j;bo[a[i]]=true;break;}k--;}}for(int i=1;i<n;i++)printf("%d ",a[i]);printf("%d\n",a[n]); } int main() {scanf("%d",&n);kangtuo1();kangtuo2();return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/AKCqhzdy/p/7612601.html
總結(jié)
以上是生活随笔為你收集整理的关于数论【康托展开及其逆运算】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个简单粗暴的爬虫 - 必应今日美图
- 下一篇: java用毫秒数做日期计算的一个踩坑记录