我一直试图在spoj上解决这个简单的问题(http://br.spoj.com/problems/GENERAL/)已经有一段时间了,但由于某些原因我一直在获得TLE(超出时间限制)。
由于问题是葡萄牙语,因此问题的简要说明就是这样(没有故事):
您将获得一个大小 N 的数组,您必须安排数组 升序,这样元素只能与之交换 距离它 k 的元素。如果阵列可以 排序然后打印排列它们所需的互换数量 升序,如果无法排序打印 impossivel 。
这是我的代码::
#include <iostream>
#include <cstdio>
using namespace std;
int a[100005];
int main() {
int t;
int n, k;
scanf("%d", &t); //number of test cases
while(t--) {
scanf("%d %d", &n, &k);
bool result = true;
int count = 0;
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
for(int i = n; i > 0; i = i - k) {
int j = 0;
for( ; j < i - k; j++) {
if(a[j] > a[j + k]) {
int temp = a[j];
a[j] = a[j + k];
a[j + k] = temp;
count++;
}
}
for( ; j < i - 1; j++) {
if(a[j] > a[j + 1]) {
result = false;
break;
}
}
if(!result)
break;
}
if(result)
printf("%d\n", count);
else
printf("impossivel\n");
}
}
我的逻辑:我对数组执行 N / k 迭代。我将循环变量 i 初始化为 N 。在每次迭代中,我检查 ik 元素与距离 k 的元素,如果它们要交换,那么我交换它们并增加所需的交换数量,否则我什么都不做。然后我检查从 ik 到 i 的元素,如果它们按升序排列,如果不是我打破循环并打印&#34; impossivel&#34;,否则我将 i 更改为 ik 并再次执行循环。根据我的逻辑,在每次迭代后,最后的 k 元素将按升序排列,如果可以对它们进行排序,因为在每一步我都会移动更大的元素。
这对你来说是否正确?如何进一步优化?在此先感谢您的帮助。 :)
答案 0 :(得分:3)
分别分为k个n / k个元素的子列表。
检查不可能状况。
不可能条件
设k = 2,
3 4 1 2是阵列
对于n / k列表,维护数组以查看O(1)中是否存在数字。
例如。间隔为2
我们可以分为两个子列表,3 1和4 2 现在我们知道sort is
1 2 3 4(使用计数排序作为1和n O(n)之间的高度)
所以,我们预计第一名是1。现在问,可以1来这里吗?如果它只在子列表中。[Y]
如果[N]说&#34;不可能&#34;
如果不可能我们就完成了其他事情。
k次合并排序,k * n / k(log(n / k))
(反转次数等于对数组进行排序的相邻互换的最小数量[已知属性] 参考: Sorting a sequence by swapping adjacent elements using minimum swaps )
方法的复杂性是n log n,很容易通过:)