首先想到对数据进行某种排序后顺序处理,sort(因此是升序)就可以了.(一开始看到算法标签里有个队列就开了优先队列,后来发现没必要而且让代码看起来很复杂)
最初想到的处理方式是遍历升序排序后的每个数据,对于每个数据遍历所有队伍(用二维数组存储所有队伍的所有成员实力),如果当前队伍的最后一名成员的实力等于当前数据+1,则把这个数据加入到此队伍中.否则(当前数据等于最后一名的成员实力或大于其实力+1)就需要就新建一支队伍.最后计算并输出最少人组的人数.
大体思路是正确的,却只过了4/10个点.
这是昨天晚上23:00发生的事情,于是只能去睡觉了.今天醒来忍不住去看了题解,发现漏掉一个细节处理.
如果输入
6 1 2 3 2 3 4
输出2,队伍为1234和23
正确答案是3,队伍为123和234
如果遍历队伍时发现可行队伍就立即入队,那么就不能保证人数最少的队伍人数取最大值.所以必须遍历所有队伍后把当前成员加入到人数最少的可行队伍.于是开了个pos[100000]记录发现的可行队伍,又来个(伪push)PushMin函数处理这个操作.最终成功的从WA走向TLE.
接下来是贪心思想的体现,我贪心地再看题解.发现想要实现每次都插入到人数最少的队伍只需要倒序遍历已有队伍,发现可行时立即插入就可以了(易证).虽然仍然是O(n2),但循环被简化了不止一点两点(这题数据很强).
此外,还意识到存储队伍只需要保存队伍人数len和最后一名成员的实力top就可以了,效率大幅提升,代码也简洁很多.
第四道绿题,虽然是看题解水过来的,以后尽力,但也不要死磕.
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, s[100010];
int idx, ans = 100000;
struct S
{
int len, top;
}t[100010];
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> s[i];
sort(s, s + n);
for(int i = 0; i < n; i++)
{
int tmp = s[i];
bool bad = true;
for(int j = idx - 1; j >= 0; j--)
if(tmp == t[j].top + 1)
{
t[j].top = tmp;
t[j].len++;
bad = false;
break;
}
if(bad)
{
t[idx].top = tmp;
t[idx].len = 1;
idx++;
}
}
for(int i = 0; i < idx; i++)
ans = min(ans, t[i].len);
printf("%d
", ans);
return 0;
}