题目大意,可以从n个带有一定power的原件中选择任意个构成一个两层的树形结构,要求第一层只有一个做根且该点的power不能改变,第二层中的原件必须可以整除根原件,如果不能整除,可以减少一定power使之满足条件。
思路:讲真很简单,就是暴力,关键就是暴力的思路!下面进行分析
1.如果有1的话那么一定就是选择所有的,1为根其他在第二层。不解释了。。。
2.如果不是1,那么我们用一个数组a[]来记录,小于或等于当前power值有多少个,例如n=3 ,1 1 2,那么a[1]=2,a[2]=3.用桶装法即可。这样就能保证,当你用i做根的时候,直接向后索搜就行,因为比i小的不可能在第二层。当检测到a[i]!=a[i-1]时,说明有新数据,这时,从j=i开始,步幅为i向后为i向后遍历!看[j,j+i-1]中间有多少个数,这些数都是一定需要改成j的!
比如 4 5 6 7,9,10,当4为根的时候5,6,7需要变成4,9,10,需要变成8!
注意一个点!j+i可能大于了最大长度(实际找到一组数据中的最大值就可以了,不需要遍历200000),所以加一个判定
tempmax+=a[min(maxpos,j+i-1)]-a[j-1]
之后每次更新即可
上代码
#include<bits/stdc++.h>
#define input freopen("input.txt","r",stdin)
using namespace std;
long long a[200002];
int main()
{
long long n,k,maxpos,i,j;
long long sum,flag=0;
while(scanf("%I64d",&n)!=EOF){
sum=flag=maxpos=0;
memset(a,0,sizeof(a));
for(i=1;i<=n;i++){
scanf("%I64d",&k);
a[k]++;
sum+=k;
if(k==1)flag=1;
maxpos=max(maxpos,k);
}
if(flag){ //存在1的情况
cout<<sum<<endl;
continue;
}
for(i=2;i<=maxpos;i++)
a[i]+=a[i-1];
long long ans=0;
for(i=2;i<=maxpos;i++){ //不存在1,i从2开始即可
if(a[i]!=a[i-1]){
long long tempmax=0;
for(j=i;j<=maxpos;j+=i)
tempmax+=j*(a[min(maxpos,j+i-1)]-a[j-1]); //注意边界!!!
ans=max(ans,tempmax);
}
}
printf("%I64d\n",ans);
}
return 0;
}
真是暴力姿势多啊!