题目:
分析:
一看这道题,诶不就二分一个d去O(n)地check不就可以了吗?
但其实是不能二分的!!因为不满足单调性。比如这组数据:a[ i ]=4 k=1 当d=3时,会在第6天砍,cost=2,d=4时,会在第4天砍,cost=0,明显d更大了,反而更优了!!!
所以说二分之前一定要考虑是否满足单调性,当自认为满足时,还应该出一点反例(这道题里面出一个小的d不满足,大的反而满足)。
那么不满足怎么办呢 ->从大到小枚举,枚举到的第一个满足的就break掉。d的上界是 min{ a[ i ] } + k (因为k>=d-minn)
当然,会T掉。
于是手推一下式子:
而ai/d(上取整)会发现有重复的,于是考虑用整除分块 (整除分块的一般证明):如何整除分块
下面是证明:
#include<bits/stdc++.h> using namespace std; #define inf 2100000000 #define N 105 #define ll long long ll k,minn=inf,ans,a[N],sum; int n; bool fl[N]; int main() { freopen("cut.in","r",stdin); freopen("cut.out","w",stdout); scanf("%d%lld",&n,&k); sum=k; for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i],minn=min(minn,a[i]); minn+=k; ll d=1; while(1){ ll tot=0; for(int i=1;i<=n;i++){ if(a[i]%d) tot+=(a[i]/d +1)*d;//讨论能不能整除 从而向上取整 else tot+=a[i]; } if(tot<=sum) ans=d; if(d>=minn) break; d=sum/(sum/(d+1)); } printf("%lld\n",ans); return 0; }