题意描述:
你有$n$个物品,每个物品大小为$a_i$,$m$个盒子,每个盒子的容积为$k$。$Maksim$先生想把物品装入盒子中。对于每个物品,如果能被放入当前的盒子中,则放入当前盒子,否则换一个新的盒子放入。为了放入尽可能多数量的物品,$Maksim$先生会从左开始扔掉一部分物品。现在,$Maksim$先生想知道,他最多能放入盒子多少物品
输入输出格式:
输入格式:
第一行,三个整数$n$,$m$,$k$,$(1≤n,m≤2 imes 10^5$,$ 1≤k≤10^9)$含义参见上文
第二行,$n$ 个数,第$i$表示$a_i$
输出格式:
一行,一个数,表示$Maksim$先生能放入盒子里的最多的物品数量
思路:
水题。。。
因为他挑选的规则一定,而删除的方式一定,所以,答案拥有单调性。
单调性:因为有一个最大合法点,在那之后都是合法的,所以再往后走的话,答案一定越来越小
所以我们的目的就是找这个最大合法点。
怎么找呢?
因为挑选方式一定,所以合法性可以O(n)验证。
这样的话,很显然就可以用一个东西叫二分答案
二分合法点就好了qwq
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rii register int i #define rij register int j using namespace std; int n,m,k; int a[200005]; bool check(int wz) { int now=0,cnt=1; for(rii=wz;i<=n;i++) { if(a[i]>k) { return false; } if(now+a[i]>k) { now=0; cnt++; } now+=a[i]; } if(cnt>m) { return false; } return true; } int main() { scanf("%d%d%d",&n,&m,&k); for(rii=1;i<=n;i++) { scanf("%d",&a[i]); } int l=1,r=n; while(l<r) { if(r-l==1) { if(check(l)==true) { break; } else { if(check(r)==true) { l=r; } else { l=n+1; } break; } } int mid=(l+r)/2; if(check(mid)==true) { r=mid; } else { l=mid; } } printf("%d",n-l+1); }