题解 CF732D 【Exams】
最后无良宣传一下博客 \(wwwwww\)
文章列表 - 地灵殿 - 洛谷博客
知识点: 贪心, 二分答案, 模拟
原题面
分析题意:
可以发现 , 复习的科目种类是没有影响的
可根据考试的不同 调整复习课目
只需要考虑复习天数是否足够即可
若只考虑 能否完成所有考试:
-
显然, 在一次考试最后一次出现时将其完成必然最优
因为这样有 最多的复习时间若在上述情况下仍然无法将所有考试完成, 则必不合法
由于答案满足单调性, 则可考虑二分答案 :
-
检查合法性时, 按照上述贪心策略,
在每一次考试 在二分量之前的最后一次出现位置 完成,
其余时间 都用来复习, 必然更优检查在考试天时, 复习天数是否足够完成考试即可
总复杂度 \(O(n\log n)\)
附 \(AC\) 代码
#include <cstdio>
#include <cstring>
#include <ctype.h>
#define int long long
const int MARX = 1e5 + 10;
//=============================================================
int N, M, first, ans, d[MARX], a[MARX], last[MARX], checker[MARX];
//=============================================================
inline int read()
{
int s = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
return s * w;
}
bool check(int lim)//检查合法性
{
memset(checker, 0, sizeof(checker));
for(int i = 1; i <= lim; i ++) last[d[i]] = i;//记录最后一次出现位置
for(int i = 1; i <= M; i ++) checker[last[i]] = a[i];//对进行考试的天进行标记
for(int i = 1, sum = 0; i <= lim; i ++)
{
if(sum < checker[i]) return 0;//不合法
if(! checker[i]) sum ++;//第i天复习
else sum -= checker[i];//第i天考试
}
return 1;
}
//=============================================================
signed main()
{
N = read(), M = read();
for(int i = 1; i <= N; i ++)
{
d[i] = read();
if(! last[d[i]]) first = i;
last[d[i]] = i;
}
for(int i = 1; i <= M; i ++)
{
a[i] = read();
//检查是否有一科考试, 在N天中都没有出现:
if(! last[i]) {printf("-1"); return 0;}
}
if(! check(N)) {printf("-1"); return 0;}//检查是否能完成
for(int l = first, r = N; l <= r;)//二分答案
{
int mid = (l + r) >> 1;
if(check(mid)) ans = mid, r = mid - 1;//检查, 调整边界
else l = mid + 1;
}
printf("%lld", ans);
}
作者@Luckyblock,转载请声明出处。

浙公网安备 33010602011771号