1. 程式人生 > >暴力搜尋-1082c-Multi-Subject Competition(cf)

暴力搜尋-1082c-Multi-Subject Competition(cf)

原題

C. Multi-Subject Competition

time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output

A multi-subject competition is coming! The competition has mm different subjects participants can choose from. That's why Alex (the coach) should form a competition delegation among his students.

He has nn candidates. For the ii-th person he knows subject sisi the candidate specializes in and riri — a skill level in his specialization (this level can be negative!).

The rules of the competition require each delegation to choose some subset of subjects they will participate in. The only restriction is that the number of students from the team participating in each of the chosen subjects should be the same.

Alex decided that each candidate would participate only in the subject he specializes in. Now Alex wonders whom he has to choose to maximize the total sum of skill levels of all delegates, or just skip the competition this year if every valid non-empty delegation has negative sum.

(Of course, Alex doesn't have any spare money so each delegate he chooses must participate in the competition).

Input

The first line contains two integers nn and mm (1n10^5 1m10^5) — the number of candidates and the number of subjects.

The next nn lines contains two integers per line: sisi and riri (1sim10^4ri10^4) — the subject of specialization and the skill level of the ii-th candidate.

Output

Print the single integer — the maximum total sum of skills of delegates who form a valid delegation (according to rules above) or 00 if every valid non-empty delegation has negative sum.

 

大意

有n個人,每個人擅長m種科目之一,要求選人蔘加某些科目,且保證每個科目參加的人數相同。(可以選擇不參加某些科目,可能有人的貢獻是負的(比如本菜))

 

思路

其實就是把相同科目的人放在一起排個序,然後維護一下字首和,最後貪心掃一下。這一題比較坑的是範圍比較大,1e5*1e5開陣列肯定存不下。一開始寫了個結構體,結果暴力部分複雜度最壞上到1e10,然後就tle了。翻題解找到大神用vector寫的題解,厚顏無恥地抄襲了一下。算是學習了一下vector,因為以前基本沒用到。

 

題解//自己稍作修改

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = int(1e5) + 7;
vector<int> project[maxn];
vector<ll> sum[maxn];
int n, m, id[maxn], max_len;

int main() {

 

//讀入
scanf("%d%d", &n, &m);
for (int i = 1, x, y; i <= n; i++) {
scanf("%d%d", &x, &y);
project[x].push_back(y);//將同科目放進一個vector裡
}

 

//對科目按人數排序
for (int j = 1; j <= m; j++) id[j] = j;
sort(id + 1, id + 1 + m, [](int x, int y) { return project[x].size() > project[y].size(); });//lambda表示式

 

//生成字首和
for (int i = 1; i <= m; i++) {
int cur = id[i];
if (project[cur].empty()) break;
int len = int(project[cur].size());

max_len = len>max_len?len:max_len;//求最大人數

sort(project[cur].begin(), project[cur].end(), greater<int>());//greater<class>內部是一個大小比較
sum[cur].resize(project[cur].size());//開一個字首和的vector
sum[cur][0] = project[cur][0];
for (int j = 1; j < len; j++) sum[cur][j] = sum[cur][j - 1] + project[cur][j];
}

 

//暴力貪心
ll ans = 0;
for (int i = 1; i <= max_len; i++) {
ll ans_buf = 0;
for (int j = 1; j <= m; j++) {
int cur = id[j];
if (project[cur].size() < i) break;//人不夠
if (sum[cur][i - 1] > 0) ans_buf += sum[cur][i - 1];//保證是正的才加
}
ans = ans>ans_buf?ans:ans_buf;
}
printf("%lld\n", ans);
return 0;
}

 

這裡用到一個lambda表示式從c++11開始支援,似乎devc編譯會warning。具體語法如下

[capture list] (parameter list){ function body };

其中除了capture list(內部可為空)和function body,其他可選。lambda表示式可以簡單理解成一個不需要宣告,沒有函式名,只需要在使用時簡單定義的函式,主要用途是看起來比較厲害而且可以簡化函式。比如本題中

sort(id + 1, id + 1 + m, [](int x, int y) { return project[x].size() > project[y].size(); });

可以換成

sort(id + 1, id + 1 + m,cmp);

再在外面定義一個

bool cmp(int x,int y){
return project[x].size()>project[y].size();
}

順便一提,使用sort對vector排序時,要保證vector開在全域性。

 

感謝Lucien的題解 https://www.lucien.ink/archives/351/