Perm

来源:互联网 发布:unity3d animation 编辑:程序博客网 时间:2024/05/21 13:56

这里写图片描述
这里写图片描述
暴力:40
算出所有的全排列即可。
正解:
先考虑这样一个问题,如何在O(n)的时间内求出一个排列的排名?
定义Rank[i]表示i位置上在a[1]-a[n] 中的排名。(从0开始计数)
很明显。
一个序列的排名即为a[n] * (n-1)!+a[n-1] * (n-2)!+…
很明显,如果我们暴力计算出来,这个数会很大。
对于第二个序列,也有上面的式子成立。
那么我们提出两个式子的公因式,计算最后输出序列的每一位的rank即可。

#include <cstdio>#include <iostream>using namespace std;int p1[9999],p2[9999];int rank1[9999],rank2[9999];int ans_rank[9999];int cnt[9999];int main(){    freopen("perm.in","r",stdin);    freopen("perm.out","w",stdout);    int n;    scanf("%d",&n);    for(int i=n;i>=1;i--)     scanf("%d",&p1[i]);    for(int i=n;i>=1;i--)     scanf("%d",&p2[i]);    for(int i=1;i<=n;i++)     for(int j=1;j<i;j++)      if(p1[j]<p1[i]) rank1[i]++;//算rank    for(int i=1;i<=n;i++)     for(int j=1;j<i;j++)      if(p2[j]<p2[i]) rank2[i]++;      for(int i=2;i<=n;i++)    {        ans_rank[i]+=rank1[i]+rank2[i];//计算答案的rank        ans_rank[i+1]+=ans_rank[i]/i;//除数不同        ans_rank[i]%=i;    }    for(int i=n;i>=1;i--)    {        int t=-1;        while(ans_rank[i]>=0)        {            t++;            if(!cnt[t]) ans_rank[i]--;//没用过这个数字        }        cnt[t]=1;        printf("%d ",t);    }}