数列还原

题目描述

牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10 个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。

输入描述:

每个输入包含一个测试用例。每个测试用例的第一行包含两个整数 n 和 k(1 <= n <= 100, 0 <= k <= 1000000000),接下来的 1 行,包含 n 个数字表示排列 A,其中等于0的项表示看不清的位置(不超过 10 个)。

输出描述:

输出一行表示合法的排列数目。

示例1

输入

5 5
4 0 0 2 0

输出

2

思路:
1.因为往数组里插入一个数,不会影响到原来的顺序对,插入一个数后,新的顺序对=原顺序对+由于插入产生的顺序对。
2.总顺序对=给定数的顺序对+未给定数的顺序对+混合时产生的顺序对。
3.未给定的数可以有各种排列,所以要求出他的全排列,以及每一种情况对应混合时产生的顺序对。

题解:

#include<cstdio>
#include<algorithm>
using namespace std;
int n;
long long k;
int arr[110];
int num[110];
int missidx[11];
int missnum[11];
int order[110][110];
int getOrderPair(int arr[], int n){
    int cnt=0;
    for(int i=0;i<n;i++){
        if(arr[i] == 0) continue;
        for(int j=i+1;j<n;j++){
            if(arr[j]==0) continue;
            if(arr[i]<arr[j]) cnt++;
        }
    }
    return cnt;
}
int main(){
    scanf("%d %lld", &n, &k);
    int cnt=0;
    for(int i=0;i<n;i++){
        scanf("%d", &arr[i]); 
        if(arr[i] == 0){
            missidx[cnt++]=i;
        }else{
            num[arr[i]] = 1;
        }
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        if(num[i]==0){
            missnum[cnt++]=i;
        }
    }
    //计算给定数组的顺序对
    int given = getOrderPair(arr, n);
    if(given>k){
        printf("%d", 0);
    }
    
    //计算未给定数据排在每个缺失的位置上产生的顺序对
    //每个缺失的数
    for(int i=0;i<cnt;i++){
        //每个缺失的位置
        for(int j=0;j<cnt;j++){
            //遍历数组
            for(int r=0;r<n;r++){
                if(arr[r] == 0) continue;
                if(r < missidx[j] && arr[r] < missnum[i]) order[missidx[j]][missnum[i]]++;
                if(r > missidx[j] && arr[r] > missnum[i]) order[missidx[j]][missnum[i]]++;
            }
        }
    }
    
    int ans = 0;
    //计算对于未给定的数的全排列所产生的顺序对
    do{
        int notGiven = getOrderPair(missnum, cnt);
        for(int i=0;i<cnt;i++){
            notGiven += order[missidx[i]][missnum[i]];
        }
        if(given + notGiven == k){
            ans++;
        }
    }while(next_permutation(missnum, missnum+cnt));
    printf("%d", ans);
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第一次来这里,是因为一位朋友在这里发布了自己的文章,于是来这里看看便知道了这里。后来在这里也先后读过几篇感兴趣的帖...
    tryagain2015阅读 2,383评论 0 0
  • 以上文字 纪念老孔 其实,所谓父道 从做事情来讲 就是初心 你来的时候的那个样子 再其实,所谓子志 就是目标 你打...
    时间爱人2016阅读 5,594评论 0 0
  • 第一周知道了人生的四种类型:忙碌奔波型、虚无主义型、享乐主义型、感悟幸福型。想要做一个真正幸福的人必须要有一个明确...
    杨润秋阅读 1,072评论 0 0

友情链接更多精彩内容