zoukankan      html  css  js  c++  java
  • 【BZOJ】3301: [USACO2011 Feb] Cow Line(康托展开)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3301

    其实这一题很早就a过了,但是那时候看题解写完也是似懂非懂的。。。。

    听zyf神犇说是康托展开,然后拖到今天才来看看。。。

    sad。。

    从不知道那里来的文档里边抄的:

    康托展开就是一种特殊的哈希函数,它的使用范围是对于n个数的排列进行状态的压缩和存储。
    X=a[n]*(n-1)!+a[n-1]*(n-2)!+…+a[i]*(i-1)!+…+a[2]*1!+a[1]*0!
    其中,a为整数,并且0<=a[i]<i(1<=i<=n)
    再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。
    例:{1,2,3,4,5}的全排列
    (1)找出第96个数
    首先用96-1得到95
    用95去除4! 得到3余23
    用23去除3! 得到3余5
    用5去除2!得到2余1
    用1去除1!得到1余0
    有3个数比它小的数是4,所以第一位是4
    有3个数比它小的数是4,但4已经在之前出现过了,所以是5(因为4在之前出现过了所以实际比5小的数是3个)
    有2个数比它小的数是3
    有1个数比它小的数是2
    最后一个数只能是1
    所以这个数是45321
    (2)找出第16个数
    首先用16-1得到15
    用15去除4!得到0余15
    用15去除3!得到2余3
    用3去除2!得到1余1
    用1去除1!得到1余0
    有0个数比它小的数是1
    有2个数比它小的数是3, 但由于1已经在之前出现过了,所以是4(因为1在之前出现过了所以实际比4小的数是2)
    有1个数比它小的数是2, 但由于1已经在之前出现过了,所以是3(因为1在之前出现过了所以实际比3小的数是1)
    有1个数比它小得数是2, 但由于1,3,4已经在之前出现过了,所以是5(因为1,3,4在之前出现过了所以实际比5小的数是1)
    最后一个数只能是2
    所以这个数是14352。

    所以我们暴力模拟找第k个没有使用过的值然后搞搞就行了。

    注意read要开longlong啊啊啊啊

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const ll getint() { ll r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    int vis[105], n, cs, a[105];
    ll m, p[50], ans;
    
    int main() {
    	read(n); read(cs);
    	p[0]=1;
    	for1(i, 1, 25) p[i]=p[i-1]*(ll)i;
    	char s[3];
    	rep(tt, cs) {
    		int j, k, t;
    		scanf("%s", s);
    		CC(vis, 0);
    		if(s[0]=='P') {
    			read(m); --m;
    			for3(i, n, 1) {
    				k=m/p[i-1]; m%=p[i-1];
    				for(j=1, t=0; t<=k; ++j) if(!vis[j]) ++t;
    				a[i]=j-1;
    				vis[j-1]=1;
    			}
    			for3(i, n, 2) printf("%d ", a[i]); printf("%d
    ", a[1]);
    		}
    		else {
    			ans=0;
    			for3(i, n, 1) read(a[i]);
    			for3(i, n, 1) {
    				for(j=1, t=0; j<a[i]; ++j) if(!vis[j]) ++t;
    				ans+=(ll)t*p[i-1];
    				vis[a[i]]=1;
    			}
    			printf("%lld
    ", ans+1);
    		}
    	}
    	return 0;
    }
    

    Description

    The N (1 <= N <= 20) cows conveniently numbered 1...N are playing 
    yet another one of their crazy games with Farmer John. The cows 
    will arrange themselves in a line and ask Farmer John what their 
    line number is. In return, Farmer John can give them a line number 
    and the cows must rearrange themselves into that line. 
    A line number is assigned by numbering all the permutations of the 
    line in lexicographic order. 

    Consider this example: 
    Farmer John has 5 cows and gives them the line number of 3. 
    The permutations of the line in ascending lexicographic order: 
    1st: 1 2 3 4 5 
    2nd: 1 2 3 5 4 
    3rd: 1 2 4 3 5 
    Therefore, the cows will line themselves in the cow line 1 2 4 3 5. 

    The cows, in return, line themselves in the configuration "1 2 5 3 4" and 
    ask Farmer John what their line number is. 

    Continuing with the list: 
    4th : 1 2 4 5 3 
    5th : 1 2 5 3 4 
    Farmer John can see the answer here is 5 

    Farmer John and the cows would like your help to play their game. 
    They have K (1 <= K <= 10,000) queries that they need help with. 
    Query i has two parts: C_i will be the command, which is either 'P' 
    or 'Q'. 

    If C_i is 'P', then the second part of the query will be one integer 
    A_i (1 <= A_i <= N!), which is a line number. This is Farmer John 
    challenging the cows to line up in the correct cow line. 

    If C_i is 'Q', then the second part of the query will be N distinct 
    integers B_ij (1 <= B_ij <= N). This will denote a cow line. These are the 
    cows challenging Farmer John to find their line number. 

    有N头牛,分别用1……N表示,排成一行。 
    将N头牛,所有可能的排列方式,按字典顺序从小到大排列起来。 
    例如:有5头牛 
    1st: 1 2 3 4 5 
    2nd: 1 2 3 5 4 
    3rd: 1 2 4 3 5 
    4th : 1 2 4 5 3 
    5th : 1 2 5 3 4 
    …… 
    现在,已知N头牛的排列方式,求这种排列方式的行号。 
    或者已知行号,求牛的排列方式。 
    所谓行号,是指在N头牛所有可能排列方式,按字典顺序从大到小排列后,某一特定排列方式所在行的编号。 
    如果,行号是3,则排列方式为1 2 4 3 5 
    如果,排列方式是 1 2 5 3 4 则行号为5 

    有K次问答,第i次问答的类型,由C_i来指明,C_i要么是‘P’要么是‘Q’。 
    当C_i为P时,将提供行号,让你答牛的排列方式。当C_i为Q时,将告诉你牛的排列方式,让你答行号。 

    Input

    * Line 1: Two space-separated integers: N and K 
    * Lines 2..2*K+1: Line 2*i and 2*i+1 will contain a single query. 
    Line 2*i will contain just one character: 'Q' if the cows are lining 
    up and asking Farmer John for their line number or 'P' if Farmer 
    John gives the cows a line number. 

    If the line 2*i is 'Q', then line 2*i+1 will contain N space-separated 
    integers B_ij which represent the cow line. If the line 2*i is 'P', 
    then line 2*i+1 will contain a single integer A_i which is the line 
    number to solve for. 

    第1行:N和K 
    第2至2*K+1行:Line2*i ,一个字符‘P’或‘Q’,指明类型。 
    如果Line2*i是P,则Line2*i+1,是一个整数,表示行号; 
    如果Line2*i+1 是Q ,则Line2+i,是N个空格隔开的整数,表示牛的排列方式。

    Output

    * Lines 1..K: Line i will contain the answer to query i. 

    If line 2*i of the input was 'Q', then this line will contain a 
    single integer, which is the line number of the cow line in line 
    2*i+1. 

    If line 2*i of the input was 'P', then this line will contain N 
    space separated integers giving the cow line of the number in line 
    2*i+1. 
    第1至K行:如果输入Line2*i 是P,则输出牛的排列方式;如果输入Line2*i是Q,则输出行号

    Sample Input

    5 2
    P
    3
    Q
    1 2 5 3 4

    Sample Output


    1 2 4 3 5
    5

    HINT

     

    Source

  • 相关阅读:
    bzoj2395: [Balkan 2011]Timeismoney
    bzoj2725: [Violet 6]故乡的梦&&bzoj4400: tjoi2012 桥
    bzoj3047: Freda的传呼机&bzoj2125: 最短路
    bzoj2734: [HNOI2012]集合选数
    bzoj2728: [HNOI2012]与非
    bzoj2730: [HNOI2012]矿场搭建
    bzoj2727: [HNOI2012]双十字
    蓝桥杯-计蒜客之节假日
    蔡基姆拉尔森计算公式
    最长公共子串与最长公共子序列
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4026896.html
Copyright © 2011-2022 走看看