1. 程式人生 > >CF1066D Boxes Packing

CF1066D Boxes Packing

names main 兩個 problem 兩個指針 oid its getc \n

傳送門

這題為什麽要用二分呢?/huaji

首先可以\(O(n)\)預處理出從某個物品\(i\)開始放,只放一個盒子,能放的最後物品的位置\(j\),只要用兩個指針維護左右端點,每次移動一下左端點同時盡量把右端點右移救星了

然後我們要放的所有物品是原來的一個後綴,所以要從後往前放,但是直接貪心放是錯的.考慮構建一棵樹,根據前面對每個\(i\)預處理出的\(j\),連\((j+1,i)\)的單向邊,然後從\(n+1\)開始dfs,記\(n+1\)的深度為0,那麽我們不能訪問深度大於\(m\)的點.記能訪問到最小的點為\(y\),答案為\(n-y+1\)

#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-5)

using namespace std;
const int N=200000+10;
il LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N],nt[N],hd[N],tot=1;
il void add(int x,int y){++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;}
int n,m,k,a[N],ans,tt=-1;
il void dfs(int x)
{
  ++tt;
  ans=max(ans,n-x+1);
  if(tt<m) for(int i=hd[x];i;i=nt[i]) dfs(to[i]);
  --tt;
}

int main()
{
  n=rd(),m=rd(),k=rd();
  for(int i=1;i<=n;i++) a[i]=rd();
  for(int i=1,su=a[1],j=1;i<=n;i++)
    {
      while(j<n&&su+a[j+1]<=k) su+=a[++j];
      add(j+1,i),su-=a[i];
    }
  dfs(n+1);
  printf("%d\n",ans);
  return 0;
}

CF1066D Boxes Packing