微软3.25笔试第一题解法
这个贪心思路有问题,感谢大佬提醒,已经发现反例
6 2 3 4 7 7 9 10
- 微软笔试第一题解法思路:
- 先用map记录每种数字的个数,若存在超出队伍总数的数字则-1
- 对于刚好每个队伍都必须放一个的数字单独记录再all_min和all_max里,作为初始化每个队伍最大最小值的初值(若不存在就是INT_MAX和INT_MIN)
- team[m][3],记录m个队伍的最小值,最大值以及剩余的位置数
- 接下来就是贪心的把小的数字从队伍0放到队伍m-1; 大的数字从m-1放到0;这样可以保证大的数字尽可能的出现一个队伍里,小的数字也尽可能出现在队伍里,使得每支队伍的max-min是最小的;
- 最后所有队伍的max-min相加得到ans
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const double inf = 1e12;
/*
12
4
5 10 4 8 3 6 5 10 4 8 3 6
2
2
1 1
4
1
1 1 1 1
4
2
1 1 2 2
9
3
3 4 5 6 7 8 8 8 10
9
3
3 4 5 5 5 8 8 8 10
9
3
3 4 5 5 5 8 8 8 10
8
2
10 10 5 5 5 8 8 8
4
4
1 2 3 4
1
1
1
*/
int a[maxn];
map<int, int> mp;
int main(){
int n, k;
scanf("%d%d", &n, &k);
for(int i=0; i<n; i++){
scanf("%d", &a[i]);
mp[a[i]] ++;
}
int m = n / k;
int all_min = INT_MAX, all_max = INT_MIN;
vector<int> del;
for(auto &item : mp){
if(item.second > m){
printf("-1\n");
return 0;
}
if(item.second == m){
all_min = min(all_min, item.first);
all_max = max(all_max, item.first);
k--;
del.push_back(item.first);
}
}
for(int &key : del) mp.erase(key);
int team[m][3];
for(int i=0; i<m; i++){
team[i][0] = all_min;
team[i][1] = all_max;
team[i][2] = k;
}
vector<pair<int, int> > v;
for(auto &item : mp){
v.push_back({item.first, item.second});
}
int l = 0, r = v.size()-1;
while(l <= r){
// up to down
int i = 0;
for(int j=0; j<v[l].second; j++){
while(i + j < m && !team[i+j][2]) i++;
if(i + j >= m){
printf("-1\n");
return 0;
}
team[i+j][0] = min(team[i+j][0], v[l].first);
team[i+j][1] = max(team[i+j][1], v[l].first);
team[i+j][2]--;
}
l++;
if(l > r) break;
// down to up
i = m-1;
for(int j=0; j<v[r].second; j++){
while(i-j >= 0 && !team[i-j][2]) i--;
if(i-j < 0){
printf("-1\n");
return 0;
}
team[i-j][0] = min(team[i-j][0], v[r].first);
team[i-j][1] = max(team[i-j][1], v[r].first);
team[i-j][2]--;
}
r--;
}
int ans = 0;
for(int i=0; i<m; i++){
// cout<<team[i][0]<<", "<<team[i][1]<<endl;
ans += team[i][1] - team[i][0];
}
printf("%d\n", ans);
return 0;
} #微软暑期实习春招##微软##笔试题目##实习##笔经#
