[CF2048D] Kevin and Competition Memories 题解
法一
提供一种非常 naive 且暴力的思路。
小于等于 Kevin 的选手没有任何贡献,扣掉。
我们发现,我们如果按轮次一个个填充这一堆比赛,实际上是可以确定一个(可能的)最优填充次序的。
先填 Kevin 会做的。这些题目不影响排名。
再按
做完了。
Q:不会 T 吗?
A:我们填充时,只关心一场比赛中,除 Kevin 会做的比赛外,最简单的题目。于是 ST 表维护即可。而对于一个
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define all(v) v.begin(), v.end()
using namespace std;
//#define filename "xxx"
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)
namespace Traveller {
const int N = 3e5+2;
int n, m, x, tmp[N], *a, b[N];
vector<int> c;
int f[N][20], LOG2[N]; //ST表
int query(int l, int r) {
if(l > r) return inf;
int k = LOG2[r - l + 1];
return min(f[l][k], f[r - (1 << k) + 1][k]);
}
void main() {
cin >> n >> m;
for(int i = 1; i <= n; ++i) scanf("%d", &tmp[i]);
x = tmp[1], a = tmp + 1;
for(int i = 1; i <= m; ++i) scanf("%d", &b[i]);
sort(a+1, a+n);
a = upper_bound(a+1, a+n, x) - 1;
n -= a - tmp;
sort(b+1, b+m+1);
c.clear();
c.push_back(0);
int easy = 0;
for(int i = 1; i <= m; ++i)
if(b[i] <= x) c.push_back(b[i]), ++easy;
else break;
for(int i = m; i >= 1; --i)
if(b[i] > x) c.push_back(b[i]);
else break;
//按c数组的顺序依次填充比赛
for(int i = 2; i <= m; ++i) LOG2[i] = LOG2[i >> 1] + 1;
for(int i = 1; i <= m; ++i) f[i][0] = c[i];
for(int k = 1; k <= 19; ++k)
for(int i = 1; i + (1 << k) - 1 <= m; ++i)
f[i][k] = min(f[i][k-1], f[i + (1 << k-1)][k-1]);
for(int k = 1; k <= m; ++k) {
int p = 1;
long long ans = 0;
for(int r = 1; r <= m / k; ++r) {
int v = query(max(p, easy+1), p+k-1);
int rank = n - (lower_bound(a+1, a+n+1, v) - a) + 2;
ans += rank;
p += k;
}
printf("%lld ", ans);
}
puts("");
}
}
signed main() {
#ifdef filename
FileOperations();
#endif
int _;
cin >> _;
while(_--) Traveller::main();
return 0;
}
法二
延续前面的观察。
我们处理出
于是排名就转化成了连续
对于
总时间复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步