题目链接:https://codeforces.com/contest/732
A - Buy a Shovel
题意:有无穷枚10元硬币和1枚r元硬币,且r是[1,9]。每个物品的单价是x元,求最少买多少件不用找钱。
题解:记得区分用r元和不用r元两种情况,分别对应模10的余数为r或者为0。现在枚举不超过10个就可以出结果。
B - Cormen --- The Best Friend Of a Man
题意:宠物狗每连续两天都需要总共走至少k步,注意对于[0,1]和[n,n+1]没有这个要求。给出一个数列表示第几天走几步,增加最少的步使得[1,2],[2,3]...[n-1,n]都满足每连续两天都需要总共走至少k步。
题解:贪心往右边的一天放。注意最后一天。
C - Sanatorium
题意:某人在食堂待了连续的一段时间,而每一天都依次吃早餐b、晚餐d、宵夜s,而他有可能会漏掉其中的一些餐。已知三种餐吃的次数,求最少漏了多少餐。
题解:可以分多种情况讨论,得到一个贪心:
假设他是从b开始吃,最后一餐吃b,则b会比另外两种多1。
假设他是从b开始吃,最后一餐吃d,则b和d会比s多1。
假设……
最后会发现一个规律,要把最少的两种都配到最多比最多的一种少1,而和他们的顺序无关(三种是完全对称的)。
*D - Exams
挺有意思的一道题。
题意:一段连续的日子,每个日子可能会有恰好一门课的Exam,或者没有任何Exam。问这段日子是否可以成功通过所有课的考试。注意每门课可能有多次Exam,只需要选一门完成。要是不参加当天的考试,则可以用来复习。第j门课在考试前需要aj天复习,问最短的通过所有考试的时间,或说明无解。
题解:一开始还在想怎么用堆(延迟决策贪心)来贪心,但是显然有个二分的算法,二分天数x,则每门课肯定选x及其之前的最后一次考试来考,这个可以O(n)得到,然后必定是贪心,到了选择的一门课的时候就要尽可能分配已有的复习资源给它,不够分配则GG。
int n, m;
int d[100005];
int a[100005];
pii lst[100005];
bool check(int len) {
for(int i = 1; i <= m; ++i)
lst[i] = {0, a[i]};
for(int i = 1; i <= len; ++i)
lst[d[i]].first = i;
for(int i = 1; i <= m; ++i) {
if(lst[i].first == 0)
return 0;
}
sort(lst + 1, lst + 1 + m);
int cnt0 = lst[1].first - 1;
for(int i = 1; i <= m; ++i) {
if(cnt0 < lst[i].second)
return 0;
else {
if(i == m)
return 1;
cnt0 -= lst[i].second;
cnt0 += (lst[i + 1].first - lst[i].first - 1);
}
}
return 0;
}
int LB;
int bs() {
int L = LB, R = n;
while(1) {
int M = (L + R) >> 1;
if(L == M) {
if(check(L))
return L;
if(check(R))
return R;
return -1;
}
if(check(M))
R = M;
else
L = M + 1;
}
}
bool vis[100005];
void test_case() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &d[i]);
int cnt = 0;
LB = -1;
for(int i = 1; i <= n; ++i) {
if(!vis[d[i]]) {
vis[d[i]] = 1;
++cnt;
if(cnt == m) {
LB = i;
break;
}
}
}
if(LB == -1) {
puts("-1");
return;
}
for(int i = 1; i <= m; ++i)
scanf("%d", &a[i]);
printf("%d\n", bs());
}
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12285846.html