问题描述
主题链接:https://codeforces.com/contest/109/problem/D
对于这个问题,我在 test41 上超出了时间限制
我猜是用的数据结构不合适,但是想了很久,不知道从哪里采用好的数据结构,请大家给点建议。
算法思路:
这种方法有点类似于选择排序。先找一个幸运数字,然后和第一个数字交换位置,然后从第二个开始,找到最小的数字,再和这个幸运数字对调,这样从第二个数字开始的最小的数字放在第一位位置,幸运数字现在在另一个位置,并记录其位置。 然后将幸运数字与第二个数字交换,然后重复上述过程。需要特别注意的是,我们排序后需要记录我们选择的幸运数字的位置,因为位置前后的过程略有不同,需要进行比较(这在代码注释中有说明)。
using namespace std;
typedef long long ll;
// Judge whether it is a lucky number. if it is a lucky number,return true,otherwise,return false.
bool judge(string x);
bool static cmp(vector<ll> a,vector<ll> b) { return a[0] < b[0]; }
int main()
{
int n;
cin >> n;
vector<ll> nums;
ll smLuckyNum = INT64_MAX;
for(int i = 0; i < n; i++)
{
ll x;
cin >> x;
nums.push_back(x);
if(judge(to_string(x)) && smLuckyNum > x) smLuckyNum = x; // Find the smallest lucky number
}
vector<vector<ll> > b; // b[i][0] stores nums[i],b[i][1] stores i index
int pos,origIndex;
bool sorted = true;
// b[i][0] stores nums[i] and b[i][1] stores i index
for(int i = 0; i < n; i++)
{
vector<ll> tmp;
tmp.push_back(nums[i]);
tmp.push_back(i);
b.push_back(tmp);
}
sort(b.begin(),b.end(),cmp); // sort by b[i][0]
// If the original array is ordered,sorted == true,sorted == false
for(int i = 0; i < n; i++)
if(b[i][1] != i) sorted = false;
// If the original array is not ordered and there is no lucky number in it,no way to sort,return -1
if(!sorted && smLuckyNum == INT64_MAX) { cout << -1 << endl; return 0; }
// If the original array is ordered,no sorting required
if(sorted) { cout << 0 << endl; return 0; }
// Find the position of the smallest lucky number,origIndex is the index of the smLuckyNum before sorting,pos is the index of the smLuckyNum after sorting
for(int i = 0; i < n; i++)
{
if(smLuckyNum == b[i][0])
{
origIndex = b[i][1];
pos = i;
break;
}
}
vector<string> ans;
// Traverse the nums array from 0 to n - 2,if i is equal to pos(the index of smLuckyNum after sorting),continue.
// We can swap the element at position i and the element at position origIndex,and record the position of LuckyNum after the swap in origIndex,// then find the smallest element from i+1 to n-1 and record the index in MINID,notice if i > pos,and nums[MINID] > nums[pos] (because there may be a large number placed at pos),the element at pos is smallest number
// if MINID < n,swap(nums[i](it is a lucky number),nums[MINID])
for(int i = 0; i < n - 1; i++)
{
if(i == pos) continue;
string res = "";
if(i != origIndex)
{
res += (to_string(i + 1) + " " + to_string(origIndex + 1)); // According to the requirement of the question,the index starts from 1,the result needs to plus one.
swap(nums[i],nums[origIndex]);
origIndex = i;
ans.push_back(res);
}
ll MINID = i + 1;
for(int j = i + 1; j < n; j++)
if(nums[MINID] > nums[j]) MINID = j;
if(i > pos && nums[MINID] > nums[pos]) MINID = pos;
if(MINID < n)
{
res = "";
res += (to_string(i + 1) + " " + to_string(MINID + 1));
swap(nums[i],nums[MINID]);
origIndex = MINID;
ans.push_back(res);
}
}
// Finally we need to compare nums[n - 1] with nums[pos] when pos != n - 1
if(pos + 1 != n && nums[pos] > nums[n - 1])
ans.push_back(to_string(pos + 1) + " " + to_string(n));
cout << ans.size() << endl;
for(int i = 0; i < ans.size(); i++)
cout << ans[i] << endl;
return 0;
}
bool judge(string x)
{
for(int i = 0; i < x.size(); i++)
if(x[i] != '4' && x[i] != '7') return false;
return true;
}
解决方法
用于查找 MINID
的嵌套循环使运行时在 n 中二次:
for(int j = i + 1; j < n; j++)
if(nums[MINID] > nums[j]) MINID = j;
当 n = 100,000 时,这将花费很长时间。您需要找到一种更好的方法来计算 MINID
。
提示:您在开始时准备 b[]
,然后永远不要使用它。