codeforces731F (思维)

来源:互联网 发布:unity3d ar ios 编辑:程序博客网 时间:2024/06/16 22:22


题意:给出一个数列.在数列中选取一个数,然后求把数列中的数变成小于他们的并且是这个数的倍数的数,求变化之后的数列的和最大值。

思路: 将每个数的个数记录下来,用前缀和记录下来。然后枚举每一个数,以他们的倍数进行计算出选取这个数后数列和。

以他们的倍数计算是:

比如以枚举a[i] ,那么在 a[i] * j 和 a[i] * (j + 1) - 1这个区间的数经过变换之后都是a[i] * j ,所以我们只要知道这些数的个数就能计算了,个数的话就要用到刚刚计算出的前缀和了。


PS :为了避免超时,同一个a[i]枚举过就不要枚举,所以用一个vis数组标记一下/。


#include<bits/stdc++.h>using namespace std;const int maxn = 2e6 + 10;#define INF 0x3f3f3f3ftypedef pair<int,int> P;typedef long long ll;int a[maxn];int cnt[maxn];ll sum[maxn + 100];int n;bool vis[maxn];int main(){    while( ~ scanf("%d",&n))    {        memset(cnt,0,sizeof(cnt));        memset(vis,false,sizeof(vis));        int maxs = 0;        for(int i = 1; i <= n;i ++)            scanf("%d",&a[i]),cnt[a[i]] ++,maxs = max(maxs,a[i]);        sum[0] = 0;        for(int i = 1; i <= maxn; i ++)            sum[i] = sum[i - 1] + cnt[i];        ll ans = 0;        for(int i = 1; i <= n; i ++)        {            if(vis[a[i]])continue;vis[a[i]] = true;            ll temp = 0;            for(int j = 2; (j  - 1)* a[i] <= maxs; j ++)            {                if(j * a[i] > maxs)                {                    temp += (sum[maxs ] - sum[(j - 1) * a[i] - 1]) * a[i] * (j - 1);                }                else                {                    temp += (sum[j * a[i] - 1] - sum[a[i]*(j - 1) - 1] )* a[i] * (j - 1);                }            }            ans = max(ans,temp);        }        printf("%I64d\n",ans);    }    return 0;}