题目
Description
对于n个元素的排列P=(p1,p2,……,pn),请你编写一个程序,在不构造出所有排列的情况下,直接输出该排列在按字典序排列的字典中的序数d(p),其中p1∈{1,2,3,…,n},1<=n<=50。例如:n=4,若p=(2,3,4,1),则d(p)=10;若p=(4,2,1,3),则d(p)=21
Input
每一行对应一个数据,格式为(n,(p1,p2,….,pn))其中n表示排列的元素个数,(p1,p2,…pn)就是这n个元素的某个排列。文件的最后一行只包含“-1”,表示输入文件结束。
Output
对于每个数据,输出对应的d(p)。所有数据的结果都输出到一行中,用逗号分开。
解题思路
虽然今天的题目都很简单,有两位同学改做B组题。但我是真的找不到规律,于是什么都没有敲。正解是康托展开:
因为数据较大,还要外加两个高精乘单精
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
int n,a[81],b[55][150],ans[150]; bool l;
void dff(int k)
{
for (int i=1;i<=145;i++)
{
b[k][i]=b[k][i]+b[k-1][i]*k;
b[k][i+1]=b[k][i+1]+b[k][i]/10;
b[k][i]=b[k][i]%10;
}
}
void df(int z,int k)
{
for (int i=1;i<=145;i++)
{
ans[i]=ans[i]+b[k][i]*z;
ans[i+1]=ans[i+1]+ans[i]/10;
ans[i]=ans[i]%10;
}
}
int main()
{
b[0][1]=1; string s;
for (int i=1;i<=50;i++) dff(i);
while (1)
{
cin>>s; int e=0,t=-1; bool bb=0;
for (int i=0;i<s.size();i++)
{
if (s[i]=='-') return 0;
if (s[i]>='0'&&s[i]<='9') { bb=1; e=e*10+s[i]-'0'; }
else if (bb==1) { a[++t]=e; e=0; bb=0;}
}
n=a[0]; a[0]=0;
memset(ans,0,sizeof(ans));
ans[1]=1;
if (l==1) printf(",");
if (n!=-1) l=1;
for (int i=1;i<n;i++)
{
int g=0;
for (int j=1;j<i;j++)
if (a[j]<a[i]) g++;
df(a[i]-1-g,n-i);
}
int q=145;
while (q>1&&ans[q]==0) q--;
for (int i=q;i>=1;i--)
printf("%d",ans[i]);
}
}