一、题目
二、解法
首先有一个等价变化:
(
a
i
−
1
)
%
d
+
1
=
a
i
−
a
i
−
1
d
×
d
(a_i-1)\% d+1=a_i-\frac{a_i-1}{d}\times d
(ai−1)%d+1=ai−dai−1×d我们再来重写一下题目表达式:
∑
d
−
a
i
+
a
i
−
1
d
×
d
≤
k
\sum d-a_i+\frac{a_i-1}{d}\times d\leq k
∑d−ai+dai−1×d≤k
d
(
n
+
∑
a
i
−
1
d
)
≤
k
+
∑
a
i
d(n+\sum \frac{a_i-1}{d})\leq k+\sum a_i
d(n+∑dai−1)≤k+∑ai由于右边的值是确定的,并且左边可以使
a
i
−
1
d
\frac{a_i-1}{d}
dai−1一定(就是多个右端点取
min
\min
min),那么外层套一个数论分块,
d
d
d就很容易算了,注意要保证
l
≤
d
≤
r
l\leq d\leq r
l≤d≤r,时间复杂度
O
(
1
e
9
×
n
)
O(\sqrt{1e9}\times n)
O(1e9×n)
#include <cstdio>
#include <iostream>
#define int long long
using namespace std;
const int M = 105;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,k,mx,ans,a[M];
signed main()
{
n=read();k=read();
for(int i=1;i<=n;i++)
{
mx=max(mx,a[i]=read());
k+=a[i];
a[i]--;
}
for(int l=1,r,s;l<=mx;l=r+1)
{
r=1e18;s=n;
for(int j=1;j<=n;j++)
if(a[j]>=l)
{
s+=a[j]/l;
r=min(r,a[j]/(a[j]/l));
}
int tmp=k/s;
if(l<=tmp) ans=max(ans,min(tmp,r));
}
if(ans<n/k) ans=n/k;
printf("%lld\n",ans);
}