题解 | # D. Price Tags #


件商品,每件商品的价格为,每件商品上都贴着原来它自己价格的标签
现在你需要选择一个数),然后将每件商品的价格变为
这时候原来的商品标签不再适用,你需要给每件商品贴上新的价格标签
但是旧标签可以复用,但只能贴在新价格和标签数字完全一样的商品上,每个标签只能用一次;不够的标签要花钱打印,每个标签打印成本是金币
求最大的收益(收益等于每件商品的新价格减去贴新标签的代价)

比如现在选择的数为,那么每件商品的新价格之和为,然后减去新价格标签的代价:所以得把原来出现的次数存下来,记为,也要把现在的出现的次数记下来,记为,那么现在需要枚举所有可能出现的标签价格,最大标签价格为,记为
所以此时的总收益为,枚举再枚举每一个价格,时间复杂度近似为,超时了

首先需要只需要从枚举到,因为如果,所有的都一直是
  • 枚举到,因为如果时,直接跳过循环,不会枚举,因为
然后只能优化的是枚举的每一个商品:现在不枚举每一件商品,而是枚举在当前的时候的值,记为,那么有的范围为,快速求范围里面出现的次数,可以用前缀和。
  • 范围里面出现的次数是的次数,即现在出现的次数,转化为了某个区间出现的次数!
那么现在时间复杂度为调和级数,约为

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


const int N = 200000 + 100;
int cnt[N], pre[N];

void solve(){
    
    memset(cnt, 0, sizeof(cnt));
    int n, y; cin >> n >> y;
    int Max = 0;
    for(int i = 1; i <= n; i ++){
        int x; cin >> x;
        cnt[x] ++;
        Max = max(Max, x);
    }    
    for(int i = 1; i < N; i ++) pre[i] = pre[i - 1] + cnt[i];
    int ans = -1000000000000000000;
    for(int x = 2; x <= Max + 1; x ++){
        int now_ans = 0;
        for(int j = 1; ; j ++){
            int l = (j - 1) * x + 1;
            int r = j * x;
            if(l > Max) break;
            r = min(r, Max);
            int now_cnt = pre[r] - pre[l - 1];
            now_ans += now_cnt * j;
            int add = max(0LL, now_cnt - cnt[j]);
            now_ans -= add * y;
        }
        ans = max(ans, now_ans);
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    cin >> tt;
    while(tt --) solve();
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务