P1065 咖啡温律录 官方题解
【部分分:测试点 1∼41\sim 41∼4】
- 这一档中温度上界只有 。一个显然的思路是枚举每一个整数温度 ,再扫描全部配方,统计满足 的配方数量。数量不少于 时,就将 标记为已经写入温律录。
- 对一次询问,直接枚举 中的全部温度并统计标记数量。设温度上界为 ,单组数据的时间复杂度为 ,空间复杂度为 。
【部分分:测试点 5∼85\sim 85∼8】
- 上一档反复判断一个温度是否落在配方区间中。我们可以考虑使用差分数组,令 ,。求前缀和后, 正好表示认可温度 的配方数量。
- 再令 ,并预处理 。询问 的答案就是 。时间复杂度为 ,空间复杂度为 。
【部分分:测试点 9∼129\sim 129∼12】
- 这一档满足 ,所以温律录恰好是全部配方区间的并。根据这一性质,我们将区间按照左端点排序,依次合并有交集或相邻的区间,可以得到若干两两分离的闭区间。
- 预处理每个合并区间包含的整数数量及其前缀和。一次询问只需二分找到与 相交的第一个和最后一个合并区间,再处理两侧不完整的部分。时间复杂度为 ,空间复杂度为 。
【正解】
- 完整数据的温度上界仍然只有 ,因此直接使用第二档的差分与两次前缀和即可。第一次前缀和求每个温度被多少张配方认可,第二次前缀和求温律录在任意前缀中包含多少个温度。
- 每个配方只产生两个差分修改,每个询问只进行一次区间作差。单组数据的时间复杂度为 ,空间复杂度为 。多组数据之间要清空本组实际使用的数组范围。
【参考代码】
#include <cstdio>#include <cstring> #define MAXV 200010 using namespace std; int c,T,n,k,q,Diff[MAXV],Pre[MAXV]; void Solve() { memset(Diff,0,sizeof(Diff)); memset(Pre,0,sizeof(Pre)); scanf("%d%d%d",&n,&k,&q); for (int i=1,l,r;i<=n;i++) { scanf("%d%d",&l,&r); Diff[l]++; Diff[r+1]--; } int Now=0; for (int i=1;i<MAXV;i++) { Now+=Diff[i]; Pre[i]=Pre[i-1]+(Now>=k); } for (int i=1,l,r;i<=q;i++) { scanf("%d%d",&l,&r); printf("%d\n",Pre[r]-Pre[l-1]); }} int main() { scanf("%d%d",&c,&T); while (T-->0) Solve(); return 0;}