BZOJ3390: [Usaco2004 Dec]Bad Cowtractors牛的报复
BZOJ3940: [Usaco2015 Feb]Censoring && BZOJ3942: [Usaco2015 Feb]Censoring

BZOJ3301: [USACO2011 Feb] Cow Line

shinbokuow posted @ Aug 18, 2015 07:34:33 PM in BZOJ with tags 排列 数学 , 906 阅读

题目大意:

(1)给定一个排列,问排列的序号.

(2)给定一个序号,要求构造出给定序号的排列.

题解:

首先要知道怎么得出排列的序号.

假如序列的长度为$n$,且第$i$个元素为$P_i$.

则序号为:$\sum_{i=1}^{n}(n-i)!\sum_{j=i+1}^{n}[P_i>P_j]$

这样的话可以$O(n^2)$算出排列的序号.

构造序列的话也是一个道理,我是暴力的,没管复杂度...

代码:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;

typedef unsigned long long llu;

int a[21],ans[21];
llu fac[21];
bool ok[21];
int main(){
	int n,Q,i,j;
	char s[10];
	cin>>n>>Q;
	llu x;
	for(fac[0]=i=1;i<=20;++i)
		fac[i]=fac[i-1]*i;
	int temp;
	while(Q--){
		scanf("%s",s);
		if(s[0]=='P'){
			cin>>x;
			--x;
			for(i=1;i<=n;++i)
				a[i]=x/fac[n-i],x-=a[i]*fac[n-i];
			memset(ok,1,sizeof ok);
			for(i=1;i<=n;++i){
				temp=0;
				for(j=1;j<=n;++j){
					if((temp+=ok[j])==a[i]+1)
						break;
				}
				ok[ans[i]=j]=0;
			}
			for(i=1;i<=n;++i){
				if(i!=1)
					putchar(' ');
				printf("%d",ans[i]);
			}
			puts("");
		}
		else{
			for(i=1;i<=n;++i)
				scanf("%d",&a[i]);
			for(x=0,i=1;i<=n;++i){
				for(temp=0,j=i+1;j<=n;++j)
					temp+=(a[i]>a[j]);
				x+=fac[n-i]*temp;
			}
			cout<<x+1<<endl;
		}
	}
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter