UOJ 021题解

Solution

显然,题目要让我们最小化:

i = 1 n a i k + i = 1 n a i   m o d   k \sum_{i=1}^n \lfloor \frac {a_i} k \rfloor+\sum_{i=1}^n a_i\ mod\ k

= i = 1 n a i k + i = 1 n ( a i k ( a i k ) ) =\sum_{i=1}^n \lfloor \frac {a_i} k \rfloor+\sum_{i=1}^n (a_i-k(\lfloor \frac {a_i} k \rfloor))

= i = 1 n a i k + i = 1 n a i k i = 1 n ( a i k ) =\sum_{i=1}^n \lfloor \frac {a_i} k \rfloor+\sum_{i=1}^n a_i-k\sum_{i=1}^n(\lfloor \frac {a_i} k \rfloor)

= i = 1 n a i ( k 1 ) i = 1 n a i k =\sum_{i=1}^n a_i-(k-1) \sum_{i=1}^n \lfloor \frac {a_i} k \rfloor

即,我们要让 ( k 1 ) i = 1 n a i k (k-1) \sum_{i=1}^n \lfloor \frac {a_i} k \rfloor 越小越好。于是,我们可以暴力枚举 k k ,然后对这个式子用整除分块优化。

故时间复杂度为 O ( i = 1 n n i ) O(\sum_{i=1}^n \lfloor \frac n i \rfloor) ,即 O ( n l o g 2 n ) O(nlog_2n)

注意本题轻微卡常,强制使用快读。

Code

#include <bits/stdc++.h>
#define int long long
#define rg register
using namespace std;
const int maxlen=1000000;

int n,tot=0,ans=1e15+7,maxv;
int a[2*maxlen+5],v[2*maxlen+5],pre[2*maxlen+5];

inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	
	while (ch<'0'||ch>'9')
	{
		if (ch=='-')  w=-w;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^'0');
		ch=getchar();
	}
	return s*w;
}

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		a[i]=read();
		v[a[i]]++;
		maxv=max(maxv,a[i]);
	}
	for (int i=1;i<=2*maxv;i++)  pre[i]=pre[i-1]+v[i];
	for (int i=1;i<=n;i++)  tot+=a[i];
	for (rg int k=1;k<=maxv;k++)
	{
		int now=0;
		for (rg int j=k;j<=maxv;j+=k)  now+=(pre[j+k-1]-pre[j-1])*(j/k);
		
		ans=min(ans,tot-(k-1)*now);
	}
	cout<<ans<<endl;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/107655421
今日推荐