康托展开 题目链接:点击这里 题目大意: 求
1
∼
N
1\sim N
1∼N 的一个给定全排列在所有
1
∼
N
1\sim N
1∼N 全排列中的排名。结果对
998244353
998244353
998244353 取模 题目分析: 对于一个长度为
n
n
n 的全排列,第
i
i
i 位有
n
−
i
+
1
n-i+1
n−i+1 种选择,因为前面
i
−
1
i-1
i−1 位确定了
i
−
1
i-1
i−1 个数,这一位就可以看作一个
n
−
i
+
1
n-i+1
n−i+1 进制 的一位,第
i
i
i 位的值就是
a
i
a_i
ai 减去它左边比它小的数的数量
−
1
-1
−1 ,显然可以用树状数组快速求解,求出这个变进制数最后还原到
10
10
10 进制即可,时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 具体细节见代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<set>#include<map>#define ll long long#define inf 0x3f3f3f3fusingnamespace std;
ll read(){
ll res =0,flag =1;char ch =getchar();while(ch<'0'|| ch>'9'){if(ch =='-') flag =-1;
ch =getchar();}while(ch>='0'&& ch<='9'){
res =(res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch =getchar();}return res*flag;}constint maxn =1e6+5;constint mod =998244353;constdouble pi =acos(-1);constdouble eps =1e-8;
ll n,a[maxn],fac[maxn],c[maxn];
ll lowbit(int u){return u&(-u);}voidadd(int pos){while(pos <= n){
c[pos]++;
pos +=lowbit(pos);}}
ll query(ll pos){
ll res =0;while(pos){
res += c[pos];
pos -=lowbit(pos);}return res;}
ll used[maxn];intmain(){
n =read();for(int i =1;i <= n;i++)
a[i]=read();
fac[0]=1;for(int i =1;i <= n;i++)
fac[i]= fac[i-1]*i%mod;
ll ans =0;for(int i =1;i <= n;i++){
ll tmp =query(a[i]);add(a[i]);
a[i]-= tmp+1;}for(int i =1;i < n;i++)
ans =(ans+a[i])*(n-i)%mod;printf("%lld\n",(ans+1)%mod);return0;}
逆康托展开 题目链接:点击这里 题目大意:
t
t
t 组数据,每组数据给定全排列长度
n
n
n ,让你求第
k
k
k 大的全排列 题目分析: 同样类似于进制转换过程将
10
10
10 进制数转回去,用权值线段树即可完成此过程,时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 具体细节见代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<set>#include<map>#define ll long long#define inf 0x3f3f3f3fusingnamespace std;intread(){int res =0,flag =1;char ch =getchar();while(ch<'0'|| ch>'9'){if(ch =='-') flag =-1;
ch =getchar();}while(ch>='0'&& ch<='9'){
res =(res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch =getchar();}return res*flag;}constint maxn =1e5+5;constint mod =1e9+7;constdouble pi =acos(-1);constdouble eps =1e-8;int t,n,tree[maxn<<2];voidpushup(int root){
tree[root]= tree[root<<1]+tree[root<<1|1];}voidbuild(int root,int l,int r){if(l == r){
tree[root]=1;return;}int mid =(l+r)>>1;build(root<<1,l,mid);build(root<<1|1,mid+1,r);pushup(root);}intquery(int root,int l,int r,int k)// 找k大值同时删除 {
tree[root]--;if(l == r)return l;int mid = l+r>>1;if(tree[root<<1]>= k)returnquery(root<<1,l,mid,k);elsereturnquery(root<<1|1,mid+1,r,k-tree[root<<1]);}intmain(){
t =read();while(t--){scanf("%d",&n);build(1,1,n);for(int i =1;i <= n;i++){int pos =read();printf("%d%c",query(1,1,n,pos+1),i==n ?'\n':' ');}}return0;}