牛客网2017校招真题编程练习--数列还原
题目描述
解题思路
首先,顺序对的个数互不影响。也就是说,对于数组A来说,增加(插入)一个数字,其A的顺序对个数不变,所以新数组A + 1的顺序对个数 = 数组A的顺序对 + 新插入的数字产生的顺序对.
进而推广到,增加c个数字,新数组A + c的顺序对 = 数组A的顺序对 + 数组c的顺序对 + 每个新插入的数字产生顺序对(共c个数字)。
所以,
1)首先计算已经给出的数字共有arrbase个顺序对;
2)然后计算缺失的数字共有canbase个顺序对;
3)最后计算全数列产生的顺序对;
对于2, 3步骤,可以将缺失的数字(数组)进行全排列。
代码
#include <unordered_set>
#include <algorithm>
#include <iostream>
//#include <bits/stdc++.h> //万能头文件(貌似VS2013不支持)
using namespace std;
//功能:实现在数组arr中(不考虑看不清的元素)找到针对位于位置pos的元素num,满足顺序对概念的元素的个数
int getorderpair(int arr[], int n, int num, int pos)
{
int sum = 0;
for (int i = 0; i<n; ++i)
{
if (!arr[i]) continue;
sum += ((arr[i]<num && i<pos) || (arr[i]>num && i>pos));
}
return sum;
}
//功能:实现在数组arr中找到满足顺序对概念的元素对的总个数
int getorderpairall(int arr[], int n)
{
int sum = 0;
for (int i = 0; i<n; ++i)
{
if (!arr[i]) continue;
sum += getorderpair(arr, n, arr[i], i);
}
return sum / 2; // each pair cal twice.
}
int main()
{
int arr[100], can[10]; // 排列数组arr,看不清的元素数组can
unordered_set<int> s;
s.clear();
int n = 0, k = 0, c = 0, base = 0, ans = 0;
int i = 0;
cin >> n >> k;
for (i = 0; i<n; ++i)
{
cin >> arr[i];
s.insert(arr[i]); //将数组array中的元素存入set s中(无重复元素)
}
for (i = 1; i<=n; ++i)
{ // find missing num
if (s.find(i) == s.end()) //find()返回给定值的定位器,如果没找到则返回end()。
can[c++] = i; //找到看不清的元素并将其存入can
}
int arrbase = getorderpairall(arr, n); //已给出的数字的顺序对数
do
{
int canbase = getorderpairall(can, c); //看不清的数字的顺序对数
int j = 0, base = 0;
for (i = 0; i<n; ++i)
{
if (arr[i]) continue;
base += getorderpair(arr, n, can[j++], i); //完整序列的顺序对数
}
if (arrbase + canbase + base == k)
++ans;
} while (next_permutation(can, can + c)); //将can进行全排列
cout << ans << endl;
return 0;
}