场上想了挺久才想到做法。
但是其实题不难。
首先发现 \(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;
}