zoukankan      html  css  js  c++  java
  • P3014 [USACO11FEB]牛线Cow Line && 康托展开

    康托展开

    康托展开为全排列到一个自然数的映射, 空间压缩效率很高。
    简单来说, 康托展开就是一个全排列在所有此序列全排列字典序中的第 (k) 大, 这个 (k) 即是次全排列的康托展开。

    康托展开是这样计算的: 对于每一位, 累计除了前面部分, 字典序小于本位的排列总数, 即

    LL cantor(){
    	LL ans = 0;
    	for(LL i = 1;i <= num;i++){
    		LL cnt = 0;
    		for(LL j = i + 1;j <= num;j++){
    			if(ask[j] < ask[i])cnt++;//后方比自己小
    			}
    		ans += cnt * fac[num - i];//这一位的排列总数
    		}
    	return ans + 1;
    	}
    

    康托逆展开

    有康托展开的计算可得, 此映射是可逆的

    bool vis[maxn];
    void reverse_cantor(LL INDEX){
    	memset(vis, 0, sizeof(vis));
    	INDEX--;
    	LL j;
    	for(LL i = 1;i <= num;i++){
    		LL t = INDEX / fac[num - i];
    		for(j = 1;j <= num;j++){
    			if(!vis[j]){
    				if(!t)break;
    				t--;
    				}
    			}
    		vis[j] = 1;
    		printf("%lld ", j);
    		INDEX %= fac[num - i];
    		}
    	puts("");
    	}
    

    P3014 [USACO11FEB]牛线Cow Line

    题意: 求康托展开和康托逆展开

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    typedef long long LL;
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const LL maxn = 25;
    LL num, na;
    LL fac[maxn];
    void get_fac(){
    	fac[0] = 1;
    	for(LL i = 1;i <= num;i++)fac[i] = fac[i - 1] * i;
    	}
    LL ask[maxn];
    LL cantor(){
    	LL ans = 0;
    	for(LL i = 1;i <= num;i++){
    		LL cnt = 0;
    		for(LL j = i + 1;j <= num;j++){
    			if(ask[j] < ask[i])cnt++;
    			}
    		ans += cnt * fac[num - i];
    		}
    	return ans + 1;
    	}
    bool vis[maxn];
    void reverse_cantor(LL INDEX){
    	memset(vis, 0, sizeof(vis));
    	INDEX--;
    	LL j;
    	for(LL i = 1;i <= num;i++){
    		LL t = INDEX / fac[num - i];
    		for(j = 1;j <= num;j++){
    			if(!vis[j]){
    				if(!t)break;
    				t--;
    				}
    			}
    		vis[j] = 1;
    		printf("%lld ", j);
    		INDEX %= fac[num - i];
    		}
    	puts("");
    	}
    int main(){
    	num = RD();na = RD();
    	get_fac();
    	char cmd;
    	for(LL i = 1;i <= na;i++){
    		cin>>cmd;
    		if(cmd == 'P')reverse_cantor(RD());
    		else{
    			for(LL j = 1;j <= num;j++)ask[j] = RD();
    			printf("%lld
    ", cantor());
    			}
    		}
    	return 0;
    	}
    
  • 相关阅读:
    剑指offer-矩形覆盖
    剑指offer-变态跳台阶
    剑指offer-跳台阶
    剑指offer-斐波那契数列
    剑指offer-旋转数组的最小数字
    剑指offer-用俩个栈实现队列
    剑指offer-重建二叉树
    剑指offer-从尾到头打印链表
    http头
    mysql-8.0解压缩版安装配置完整过程
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9410163.html
Copyright © 2011-2022 走看看