【二分 优先队列】P3611 [USACO17JAN] Cow Dance Show S|普及+
本文涉及的基础知识点
C++二分查找
C++堆(优先队列)
[USACO17JAN] Cow Dance Show S
题面翻译
题目描述
经过几个月的排练,奶牛们基本准备好展出她们的年度舞蹈表演。今年她们要表演的是著名的奶牛芭蕾——“cowpelia”。
表演唯一有待决定的是舞台的尺寸。一个大小为 K K K 的舞台可以支持 K K K 头牛同时在舞台上跳舞。在牛群中的 N N N 头牛按照她们必须出现在舞蹈中的顺序方便地编号为 1 , 2 , … , N 1,2,\dots,N 1,2,…,N。第 i i i 头牛计划跳 d i d_i di 的特定持续时间。
一开始,第 1 , 2 , … , K 1,2,\dots,K 1,2,…,K 头牛出现在舞台上并开始跳舞。当这些牛中的某一头牛首先完成了她的部分,她会马上离开舞台并且第 K + 1 K+1 K+1 头牛会出现在舞台上并开始跳舞。所以,舞台上总有 K K K 头奶牛在跳舞(直到表演的尾声,奶牛不够的时候)。当最后一头奶牛完成了她的舞蹈部分,表演结束,共花了 T T T 个单位时间。
显然, K K K 的值越大, T T T 就越小。由于表演不能拖太长,你得知了指定 T T T 的最大可能值的上限 T m a x T_{max} Tmax。请根据这个约束,确定 K K K 的最小值。
输入格式
第一行包括 N N N 和 T m a x T_{max} Tmax 两个整数。
接下来的 N N N 行,第 i i i 行给出了第 i i i 头牛跳舞的持续时间 d i d_i di。第 i i i 行包括一个整数 d i d_i di。
保证 K = N K=N K=N 时表演会按时完成。
输出格式
输出在表演时间不大于 T m a x T_{max} Tmax 时的 K K K 的最小可能值。
提示说明
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 4 1 \le N \le 10^4 1≤N≤104, T m a x ≤ 1 0 6 T_{max} \le 10^6 Tmax≤106, 1 ≤ d i ≤ 1 0 5 1 \le d_i \le 10^5 1≤di≤105。
题目描述
After several months of rehearsal, the cows are just about ready to put on their annual dance performance; this year they are performing the famous bovine ballet “Cowpelia”.
The only aspect of the show that remains to be determined is the size of the stage. A stage of size K K K can support K K K cows dancing simultaneously. The N N N cows in the herd ( 1 ≤ N ≤ 10 , 000 1 \leq N \leq 10,000 1≤N≤10,000) are conveniently numbered 1 … N 1 \ldots N 1…N in the order in which they must appear in the dance. Each cow i i i plans to dance for a specific duration of time d ( i ) d(i) d(i). Initially, cows 1 … K 1 \ldots K 1…K appear on stage and start dancing. When the first of these cows completes her part, she leaves the stage and cow K + 1 K+1 K+1 immediately starts dancing, and so on, so there are always K K K cows dancing (until the end of the show, when we start to run out of cows). The show ends when the last cow completes her dancing part, at time T T T.
Clearly, the larger the value of K K K, the smaller the value of T T T. Since the show cannot last too long, you are given as input an upper bound T m a x T_{max} Tmax specifying the largest possible value of T T T. Subject to this constraint, please determine the smallest possible value of K K K.
输入格式
The first line of input contains N N N and T m a x T_{max} Tmax, where T m a x T_{max} Tmax is an integer of value at most 1 million.
The next N N N lines give the durations d ( 1 ) … d ( N ) d(1) \ldots d(N) d(1)…d(N) of the dancing parts for cows 1 … N 1 \ldots N 1…N. Each d ( i ) d(i) d(i) value is an integer in the range 1 … 100 , 000 1 \ldots 100,000 1…100,000.
It is guaranteed that if K = N K=N K=N, the show will finish in time.
输出格式
Print out the smallest possible value of K K K such that the dance performance will take no more than T m a x T_{max} Tmax units of time.
样例 #1
样例输入 #1
5 8
4
7
8
6
4
样例输出 #1
4
二分查找+优先队列
二分查找:寻找首端
参赛返回:[1,N]
优先队列(大根堆)记录舞台上奶牛结束时间。
堆定元素如果大于TMax,返回假。
否则加入新奶牛。
代码
核心代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;scanf("%d", &n);vector<T> ret(n);for(int i=0;i < n ;i++) {cin >> ret[i];}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 12 * 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;}inline void write(char ch){*m_p++ = ch;}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);}
private:char puffer[N], * m_p;
};template<int N = 12 * 1'000'000>
class CInBuff
{
public:inline CInBuff() {fread(buffer, 1, N, stdin);}inline int Read() {int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);return f ? -x : x;}
private:char buffer[N], * S = buffer;
};template<class TSave, class TRecord >
class CRangUpdateLineTree
{
protected:virtual void OnQuery(const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) = 0;virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
};template<class TSave, class TRecord >
class CVectorRangeUpdateLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
public:CVectorRangeUpdateLineTree(int iEleSize, TSave tDefault, TRecord tRecordNull) :m_iEleSize(iEleSize), m_save(iEleSize * 4, tDefault), m_record(iEleSize * 4, tRecordNull) {m_recordNull = tRecordNull;}void Update(int iLeftIndex, int iRightIndex, TRecord value){Update(1, 0, m_iEleSize - 1, iLeftIndex, iRightIndex, value);}void Query(int leftIndex, int rightIndex) {Query(1, 0, m_iEleSize - 1, leftIndex, rightIndex);}//void Init() {// Init(1, 0, m_iEleSize - 1);//}TSave QueryAll() {return m_save[1];}void swap(CVectorRangeUpdateLineTree<TSave, TRecord>& other) {m_save.swap(other.m_save);m_record.swap(other.m_record);std::swap(m_recordNull, other.m_recordNull);assert(m_iEleSize == other.m_iEleSize);}
protected://void Init(int iNodeNO, int iSaveLeft, int iSaveRight)//{// if (iSaveLeft == iSaveRight) {// this->OnInit(m_save[iNodeNO], iSaveLeft);// return;// }// const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;// Init(iNodeNO * 2, iSaveLeft, mid);// Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);// this->OnUpdateParent(m_save[iNodeNO], m_save[iNodeNO * 2], m_save[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);//}void Query(int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {this->OnQuery(m_save[iNodeNO], iSaveLeft, iSaveRight);return;}if (iSaveLeft == iSaveRight) {//没有子节点return;}Fresh(iNodeNO, iSaveLeft, iSaveRight);const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (mid >= iQueryLeft) {Query(iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);}if (mid + 1 <= iQueryRight) {Query(iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);}}void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value){if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight)){this->OnUpdate(m_save[iNode], iSaveLeft, iSaveRight, value);this->OnUpdateRecord(m_record[iNode], value);return;}if (iSaveLeft == iSaveRight) {return;//没有子节点}Fresh(iNode, iSaveLeft, iSaveRight);const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (iMid >= iOpeLeft){Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);}if (iMid + 1 <= iOpeRight){Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);}// 如果有后代,至少两个后代this->OnUpdateParent(m_save[iNode], m_save[iNode * 2], m_save[iNode * 2 + 1], iSaveLeft, iSaveRight);}void Fresh(int iNode, int iDataLeft, int iDataRight){if (m_recordNull == m_record[iNode]){return;}const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_record[iNode]);Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_record[iNode]);m_record[iNode] = m_recordNull;}vector<TSave> m_save;vector<TRecord> m_record;TRecord m_recordNull;const int m_iEleSize;
};template<class INDEX_TYPE>
class CBinarySearch
{
public:CBinarySearch(INDEX_TYPE iMinIndex, INDEX_TYPE iMaxIndex, INDEX_TYPE tol = 1) :m_iMin(iMinIndex), m_iMax(iMaxIndex), m_iTol(tol) {}template<class _Pr>INDEX_TYPE FindFrist(_Pr pr){auto left = m_iMin - m_iTol;auto rightInclue = m_iMax;while (rightInclue - left > m_iTol){const auto mid = left + (rightInclue - left) / 2;if (pr(mid)){rightInclue = mid;}else{left = mid;}}return rightInclue;}template<class _Pr>INDEX_TYPE FindEnd(_Pr pr){INDEX_TYPE leftInclude = m_iMin;INDEX_TYPE right = m_iMax + m_iTol;while (right - leftInclude > m_iTol){const auto mid = leftInclude + (right - leftInclude) / 2;if (pr(mid)){leftInclude = mid;}else{right = mid;}}return leftInclude;}
protected:const INDEX_TYPE m_iMin, m_iMax, m_iTol;
};class Solution {
public:int Ans(int T, vector<int>& a) {const int N = a.size();auto Check = [&](int mid) {priority_queue<int, vector<int>, greater<int>> maxHeap;int i = 0;for (; i < mid; i++) {maxHeap.emplace(a[i]);}while (maxHeap.size()) {if (maxHeap.top() > T) { return false; }if (i < N) {maxHeap.emplace(maxHeap.top() + a[i]); i++;}maxHeap.pop();}return true;};return CBinarySearch<int>(1, N).FindFrist(Check);}
};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG int n,T;cin >> n >> T ;auto a = Read<int>(n); auto res = Solution().Ans(T,a);cout << res;
#ifdef _DEBUG /*printf("T=%d,", T);Out(a, "a=");*///Out(edge, "edge=");
#endif // DEBUG return 0;
}
单元测试
int T;vector<int> a;TEST_METHOD(TestMethod11){T = 8, a = { 4,7,8,6,4 };auto res = Solution().Ans(T,a);AssertEx(4, res);}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。