CF2144D
场上想了挺久才想到做法。
但是其实题不难。
首先发现 \(c_i\) 的数据范围不大,可以考虑枚举 \(x\)。
接着考虑如何每次枚举 \(x\) 完之后,计算当前 \(x\) 的答案。
用一个桶记录一下每个 \(c_i\) 出现的次数。
接着对于一个 \(x\),我们用一个变量 \(j\) 遍历 \(x\) 的倍数,可以发现能重用的标签对应的原标签范围为 \(jx\sim(j+1)x-1\)。
所以对桶再做一个前缀和就可以快速计算每个 \(x\) 的答案了。
复杂度是 \(O(M\log M)\) 的。
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fir first
#define sec second
//#define re register
#define il inline
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define int ll
using namespace std;
const int N=200005;
int t,n,y,c[N],f[N],pre[N];
signed main(){
ios;
cin>>t;
while(t--){
cin>>n>>y;
memset(f,0,sizeof f),memset(pre,0,sizeof pre);
int mx=0,ans=-1e18;;
for(int i=1;i<=n;i++){cin>>c[i];mx=max(mx,c[i]);}
for(int i=1;i<=n;i++)if(c[i]<=mx)f[c[i]]++;
for(int i=1;i<=mx;i++)pre[i]=pre[i-1]+f[i];
for(int x=2;x<=mx+1;x++){
int sum=0,re=0;
for(int k=1;x*k-x+1<=mx;k++){
int l=x*k-x+1,r=min(x*k,mx);
int cnt=pre[r]-pre[l-1];
if(cnt>0)sum+=k*cnt,re+=min(f[k],cnt);
}
ans=max(ans,sum-y*(n-re));
}
cout<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号