突破点1:仔细审题能发现交谈对总是相互挨着,那么一定是横坐标相等纵坐标差一或者纵坐标相等横坐标差一,又发现分割线横线和竖线的数量是给定的,那么这两种线互不干扰,那么从二维转换为一维问题。就用两个数组分别存交谈对数。
突破点2:收集横坐标i和i+1之间有交谈对的数量,纵坐标也是如此,那么最后分别对两个数组贪心找前k个或者前l个最多的交谈对,在其中间有一条竖线或者横线,具体情况具体分析。
突破点3:那么到这里我们发现最后排序完可能丢失了原来的顺序,现在又要按升序输出满足条件的k/l个位置。那么我们在定义vector数组时不能只存交谈对数,还要存原始下标。最后排序先按照交谈对数从大到小满足贪心思想,尽可能多隔开。再对前k/l按照存的原始下标升序排序,最后输出前k/l项即可。
这里时间复杂度为O(m+n+d+logm+logn)。
最后附上代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
//pair<int,int>一个参数是位置下标,另一个是位置的交谈对个数
//这里不以vector下标做索引而单独存一个下标是因为需要排序找到前个k/l个
//最大值后还能根据存的下标保证严格升序
void solve() {
int n, m, k, l, d;
cin >> n >> m >> k >> l >> d;
vector<PII>row(n + 1, {0, 0});
vector<PII>col(m + 1, {0, 0});
for (int i = 1; i <= n; i++) {
row[i].first = i;
}
for (int j = 1; j <= m; j++) {
col[j].first = j;
}
while (d--) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
if (x1 == x2) {
col[min(y1, y2)].second++;
} else if (y1 == y2) {
row[min(x1, x2)].second++;
}
}
//先按照最多的交谈对个数按降序排序
sort(row.begin() + 1, row.end(), [](PII & a, PII & b) {
return a.second > b.second;
});
sort(col.begin() + 1, col.end(), [](PII & a, PII & b) {
return a.second > b.second;
});
//再按照原下标的大小升序排序,注意这里只排前k/l项!!!
sort(row.begin() + 1, row.begin()+k+1);
sort(col.begin() + 1, col.begin()+l+1);
for(int i=1;i<=k;i++)cout<<row[i].first<<" ";
cout<<endl;
for(int i=1;i<=l;i++)cout<<col[i].first<<" ";
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
solve();
return 0;
}

京公网安备 11010502036488号