zoukankan      html  css  js  c++  java
  • 洛谷P5367 【模板】康托展开

    题目链接:https://www.luogu.com.cn/problem/P5367

    康拓展开:建立起排列和自然数的双射关系,可以用来求解排列的哈希值

    设给定一个排列 (a),则 (a) 在排列集合中的排名为:

    [ans=∑_{i=1}^npi∗(n−i)! ]

    其中 (p_i) 表示小于 (a[i]) 的没有出现过的数的次数 (可以用树状数组求解)

    时间复杂度 (O(nlogn))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1000100;
    const int M = 998244353;
    
    int n;
    int a[maxn], c[maxn];
    int fac[maxn];
    
    void add(int k, int x){
    	for(; x <= n ; x += x & (-x)){
    		c[x] += k;
    	}
    }
    
    int query(int x){
    	int res = 0;
    	for(; x ; x -= x & (-x)){
    		res += c[x];
    	}
    	return res;
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	n = read();
    	fac[0] = 1;
    	for(int i = 1 ; i <= n ; ++i){ fac[i] = 1ll * fac[i - 1] * i % M; } 
    	for(int i = 1 ; i <= n ; ++i) add(1, i);
    	
    //	printf("%d
    ",query(n));
    	for(int i = 1 ; i <= n ; ++i) a[i] = read();
    	
    	int ans = 1;
    	for(int i = 1 ; i <= n ; ++i){
    		int p = 1ll * (query(a[i]) - 1) * fac[n - i] % M;
    		ans = (ans + p) % M;
    		add(-1, a[i]);
    	}
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    

    逆康托展开

    将求解康托展开的过程反过来,每次对 (ans) 除和模 ((n-i)!) 即可
    需要求解动态第 (k) 小元素,使用平衡树

  • 相关阅读:
    hadoop cdh5的pig隐式转化(int到betyarray)不行了
    贝叶斯定理与朴素贝叶斯分类器
    我所见过最全的互联网广告相关介绍
    使用Python做简单的字符串匹配
    awk:快速入门(简单实用19例+鸟哥书内容)
    聚类算法小结
    dubbo 实战
    Mysql查询场景
    深入学习树---二叉树基础
    mysql 索引
  • 原文地址:https://www.cnblogs.com/tuchen/p/14024358.html
Copyright © 2011-2022 走看看