康托展开,求全排列的排名

来自校内赛的一道题的题解

题目:输入一个n和两个n的全排列,求两个全排列的排名差的绝对值,排名为字典序排名

思路:依据康托展开,思路就是从第一个数组开始遍历,找到这个数字在没有出现过的数字里的排名,之后ans+=(排名数-1)*(n-i)!,其中i为循环次数,从1开始。最后对得到的ans+1.

        我们只需要用一个vis数组记录之前出现过的数字即可正确得到排名

    AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5+100;

int vis[10]; int x[100];
int y[100];
void fast ()
{ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);}

int pail (int a ){        //计算阶乘
	if(a ==0) return 1;
	else {
		int ans =1;
		for(int i=1;i<=a;i++)	
			ans*=i;
		return ans;	
	}
}

signed main ()
{
	fast();
	int n; cin>>n;
	int cnt1 =1,cnt2 =1;
	int ans1=0; int ans2 =0;
	for(int i=1;i<=n;i++){
		cin>>x[i];
		for(int j=1;j<=n;j++){
			if(x[i]>j &&vis[j]==0){  //如果大于这个数字且这个数字没有出现过
				cnt1++; 
			}
		}
		ans1 += (cnt1-1)*pail(n-i);
		vis[x[i]] =1;
		cnt1=1;             //初始化cnt1
	}
	ans1+=1;   //注意+1
	memset(vis,0,sizeof(vis));
	 for (int i=1;i<=n;i++){       //同上一个循环
		cin>>y[i];
	 	for(int j=1;j<=n;j++){
	 		if(y[i]>j &&vis[j]==0){
	 			cnt2++; 
	 		}
	 	}
	 	ans2 += (cnt2-1)*pail(n-i);
	 	vis[y[i]] =1;
	 	cnt2=1;
	 }
	ans2++;   //注意+1
	cout<<abs(ans1-ans2);
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值