bzoj3301: [USACO2011 Feb] Cow Line

新姿势康托展开。。

------------------------------------

裸的康托展开&逆康托展开

  康托展开就是一种特殊的hash,且是可逆的……

  康托展开计算的是有多少种排列的字典序比这个小,所以编号应该+1;逆运算同理(-1)。

  序列->序号:(康托展开)

    对于每个数a[i],数比它小的数有多少个在它之前没出现,记为b[i],ans=1+b[i](ni)!ans=1+∑b[i]∗(n−i)!

  序号->序列:(逆康托展开)

    求第x个排列所对应的序列,先将x-1,然后对于a[i],x(ni)!⌊x(n−i)!⌋即为在它之后出现的比它小的数的个数,所以从小到大数一下有几个没出现的数,就知道a[i]是第几个数了。

------------------------------------

 1 #include<bits/stdc++.h>
 2 #define rep(i,l,r) for(int i=l;i<=r;++i)
 3 using namespace std;
 4 const int N=25;
 5 int n,Q,a[N],f[N];
 6 typedef long long ll;
 7 char s[10];
 8 ll ans,sum,fac[N],x;
 9 int main(){
10     scanf("%d%d",&n,&Q);
11     fac[1]=1; fac[0]=1;
12     rep(i,2,n) fac[i]=fac[i-1]*i;
13     while(Q--){
14         scanf("%s",s);
15         if(s[0]=='P'){
16             scanf("%lld",&x);--x;
17             memset(f,0,sizeof f);
18               rep(i,1,n){
19                 int t=x/fac[n-i],j,k;
20                 for(k=1,j=0;j<=t;k++) if (!f[k]) j++;
21                    f[k-1]=1; a[i]=k-1;
22                   x%=fac[n-i];
23               }
24               rep(i,1,n-1) printf("%d ",a[i]);
25                printf("%d\n",a[n]);
26         }else {
27             memset(f,0,sizeof f); ans=1; 
28             rep(i,1,n) {
29                 scanf("%lld",&x);
30                 f[x]=1;
31                 sum=0;
32                 rep(j,1,x-1) sum+=(!f[j]);
33                 ans+=sum*fac[n-i];
34             }
35             printf("%lld\n",ans);
36         }
37     }
38 }
View Code

 

posted @ 2017-02-10 21:18  Bloodline  阅读(266)  评论(0编辑  收藏  举报