暑假考试题4:砍树 cut(整除分块)

 

题目:

分析:

一看这道题,诶不就二分一个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(上取整)会发现有重复的,于是考虑用整除分块 (整除分块的一般证明):如何整除分块

这道题的整除分块待证明。。。

扫描二维码关注公众号,回复: 7094584 查看本文章
#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;
}

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11409070.html