一个数列 P P P 中有 n n n 个数。小蓝从中选择位置连续的 k k k 个数,并对这 k k k 个数进行升序排列。求排序后的数列有多少种?
输入描述
n k n\ k n k
P 0 P 1 . . . P n − 1 P_0\ P_1...P_{n-1} P0 P1...Pn−1
其中: 所有的输入都是整数, P 0 , P 1 , . . . . . . , P n − 1 P_0,P_1,......,P_{n-1} P0,P1,......,Pn−1数值都不相同。
输出格式
部分排序后数列的排列数。
数据范围
2 ≤ n ≤ 100 2 \le n \le 100 2≤n≤100
2 ≤ k ≤ n 2\le k\le n 2≤k≤n
0 ≤ P i ≤ n − 1 0\le P_i\le n-1 0≤Pi≤n−1
输入样例
5 3
0 2 1 4 3
输出样例
2
提示
从原数列抽取连续3个数排序后有2种可能性: ( 0 , 1 , 2 , 4 , 3 ) (0,1,2,4,3) (0,1,2,4,3)和 ( 0 , 2 , 1 , 3 , 4 ) (0,2,1,3,4) (0,2,1,3,4)。
题中给出的数据范围较小,因此可以使用暴力枚举的方式:枚举数列中所有连续的 k k k 个数的组合,然依次对每一个进行排序。
但是排序后可能后产生重复的数列。例如:对于输入样例 [ 02143 ] [0 2 1 4 3] [02143]中 [ 021 ] [0 2 1] [021]和 [ 214 ] [2 1 4] [214]进行排序,得到的数列都是 [ 01243 ] [01243] [01243]。
继续分析,由于数列中数值都不相同,所以排序后只可能在相邻两项中产生相同结果。因此只需记录上次产生的数列,然后和本次的排序结果进行比较即可。
O ( n 2 l o g n ) O(n^2logn) O(n2logn)
#include
#include
#include
using namespace std;
const int N = 110;
//b记录本次排序后的数列
//last记录上次排序得到的数列
int a[N], b[N], last[N];
int n, k;
//检查两个数列是否相同
bool check(int a[], int b[])
{
for(int i = 0; i < n; i ++)
if(a[i] != b[i]) return false;
return true;
}
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i ++) cin >> a[i];
//将原数列a拷贝到last中
memcpy(last, a, sizeof a);
int sum = 0;
//枚举所有连续k个数的起始位置
for(int i = 0; i <= n - k; i ++)
{
//将a拷贝到b中进行排序
memcpy(b, a, sizeof a);
sort(b + i, b + i + k);
//排序后与上一个序列不相同
if(!check(last, b)) sum ++;
//将b拷贝到last
memcpy(last, b, sizeof b);
}
cout << sum << endl;
return 0;
}