题意:
有n类物品,第i种物品权值为$val(i)$,有$cnt(i)$个,现在你可以选出一些物品排成一个序列(假设有m个),
记第i个物品种类为$x_i$,最大化$sum_{i=1}^m{i * val(x_i)}$
解法:
只要将物品分为两类即可。
对于$val(i) ge 0$的直接从小到大排列插入序列末端即可,然后在序列首端插入物品,
记当前后缀和为$suffixsum$。
接下来从大到小插入$val(i)<0$的物品,每插入一个会产生$suffixsum+val(i)$的答案贡献,并且影响$suffixsum$
贪心正确性显然,接下来考虑加速插入物品的过程,
一次性插入t个i类物品不更新$suffixsum$对答案的贡献为$t*suffixsum + frac{t*(t+1)}{2}*val(i)$,
且有$t le frac{-suffixsum}{val(i)}$。
从而$O(nlogn)$解决此问题。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 #define N 1010 7 #define LL long long 8 9 using namespace std; 10 11 int val[N],cnt[N],a[N]; 12 13 bool cmp(int a,int b) 14 { 15 return val[a]<val[b]; 16 } 17 18 LL S(LL n) 19 { 20 return n*(n+1LL)/2LL; 21 } 22 23 int main() 24 { 25 int T,n; 26 scanf("%d",&T); 27 while(T--) 28 { 29 scanf("%d",&n); 30 for(int i=1;i<=n;i++) 31 scanf("%d%d",&val[i],&cnt[i]),a[i]=i; 32 sort(a+1,a+n+1,cmp); 33 int sum=0; 34 LL ans=0,suffix_sum=0; 35 for(int i=1;i<=n;i++) 36 { 37 if(val[a[i]]<0) continue; 38 sum += cnt[a[i]]; 39 ans += (S(sum)-S(sum-cnt[a[i]])+0LL) * (LL)val[a[i]]; 40 suffix_sum += cnt[a[i]] * (LL)val[a[i]]; 41 } 42 for(int i=n;suffix_sum>0 && i>=1;i--) 43 { 44 if(val[a[i]]>=0) continue; 45 LL tmp = (-suffix_sum)/val[a[i]]; 46 tmp = min(tmp, (LL)cnt[a[i]]); 47 ans += tmp*suffix_sum + S(tmp)*val[a[i]]; 48 suffix_sum += tmp*val[a[i]]; 49 } 50 cout << ans << endl; 51 } 52 return 0; 53 }