Lotus and Characters (stronger)

题意:

有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 }
View Code
原文地址:https://www.cnblogs.com/lawyer/p/6568411.html