题目大意:
n的排列,K个询问
为P时,读入一个数x,输出第x个全排列
为Q时,读入N个数,求这是第几个全排列
思路:
不知道康拓展开是什么,手推了一个乱七八糟的东西
首先可以知道
把排列看成是一个每一位进制不同的数
每一位进制可以看做是:
(n-1)! (n-2)! ...... 2 1 1
然后对于第一种询问
像正常进制转换一样,处理出每一位应该填第几个数
这时需要处理一下哪些数可以被取到
然后取可以取到的数里的第“几”个 每一位输出就可以了
对于第二种询问
直接一位一位减,同样在处理的时候记录哪些数可以被取到
答案+=每一位进制*该位置权值
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 using namespace std; 13 inline ll read() 14 { 15 ll x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 ll n,T,t[22],x,pos,vis[22],i,cnt,tot,res,f; 21 char ch[2]; 22 int main() 23 { 24 n=read(); 25 t[n]=t[n-1]=1; 26 for(i=n-2;i;i--) t[i]=t[i+1]*(n-i); 27 //cout<<t[1]<<endl; 28 for(T=read();T;T--) 29 { 30 scanf("%s",ch); 31 pos=1,tot=f=0; 32 memset(vis,0,sizeof(vis)); 33 if(ch[0]=='P') 34 { 35 x=read()-1; 36 while(x) 37 { 38 while(x<t[pos]) 39 { 40 for(i=1;i<=n;i++) if(!vis[i]) 41 { 42 if(f) printf(" %lld",i);else {printf("%lld",i);f=1;} 43 break; 44 } 45 vis[i]=1; 46 pos++; 47 } 48 while(x>=t[pos]) x-=t[pos],cnt++; 49 for(i=1;i<=n&&cnt!=-1;i++) if(!vis[i]) cnt--; 50 vis[i-1]=1,tot++,cnt=0,pos++; 51 if(f) printf(" %lld",i-1);else {printf("%lld",i-1);f=1;} 52 } 53 if(tot!=n) 54 for(i=1;i<=n;i++) 55 if(!vis[i]) 56 if(f) printf(" %lld",i);else {printf("%lld",i);f=1;} 57 puts(""); 58 } 59 else 60 { 61 res=0; 62 for(i=1;i<=n;i++) 63 { 64 x=read(); 65 for(ll j=1;j<x;j++) if(!vis[j]) cnt++; 66 res+=t[i]*cnt; 67 vis[x]=1,cnt=0; 68 } 69 printf("%lld ",res+1); 70 } 71 } 72 }