题目概述
有
n
个竹子,每个竹子刚开始高度为
解题报告
除法分块性质: ⌊ni⌋ 排序去重之后是 O(n√) 的。
简单说明:一个数的因子是 O(n√) 的。
先推式子喽:
∑i=1n{d−[(ai−1) mod d+1]}≤k∑i=1n[d−(ai−1−d⌊ai−1d⌋+1)]≤knd−∑i=1n(ai−d⌊ai−1d⌋)≤knd+d∑i=1n⌊ai−1d⌋≤k+∑i=1nai
根据除法分块的性质,
⌊ai−1d⌋
只有
ai−−√
种情况,而
n
个则有
不妨继续推:
d∑i=1n⌊ai+d−1d⌋≤k+∑i=1nai∑i=1n⌊ai+d−1d⌋≤k+∑ni=1aid∑i=1n⌊ai+d−1d⌋≤⌊k+∑ni=1aid⌋
由于右边只有 k+∑ni=1ai−−−−−−−−−√ 块,而每块中 d 越大,左边的式子越小(右边不变),所以每块中有价值的只有最大的 d ,那么还是暴力枚举即可。效率 O(nk+∑ni=1ai−−−−−−−−−√) ,比之前的要好一些,也没什么细节处理。
示例程序
我真的没有在水博客……
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100;
int n,a[maxn+5];LL K,ans;
bool check(LL d) {LL sum=0;for (int i=1;i<=n;i++) sum+=(a[i]-1)/d+1;return sum<=K/d;}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%lld",&n,&K);for (int i=1;i<=n;i++) scanf("%d",&a[i]),K+=a[i];
for (LL l=1,r;l<=K;l=r+1) if (check(r=K/(K/l))) ans=r;
return printf("%lld\n",ans),0;
}