Description
Input
Output
Sample Input
3 5 4 1 4 2 2 3 2 1
Sample Output
7
Data Constraint
Solution
我们不妨初始时设 ans = ∑ 𝐾𝑖 ∗ 𝐵𝑖 𝑛 𝑖=1 。
考虑一次两个套娃𝑖和𝑗的合并,即套娃𝑖装到套娃𝑗里面,对答案的贡献是 ans = ans − 𝐵𝑗 ∗ 𝐼𝑛𝑗 + 𝐵𝑗 ∗ (𝐼𝑛𝑗 − 𝑂𝑢𝑡𝑖)
即 ans −= 𝐵𝑗 ∗ 𝑂𝑢𝑡𝑖
那我们尝试用贪心的思想。 我们首先把𝐵𝑖由大到小排序,对于每个𝐵𝑖,找一个最大的可用的𝑂𝑢𝑡𝑗。 怎么证明它是对的呢?
现在有𝐵𝑖、𝐵𝑗、𝑂𝑢𝑡𝑘、𝑂𝑢𝑡𝑙,有(𝐵𝑖 > 𝐵𝑗),(𝑂𝑢𝑡𝑘 > 𝑂𝑢𝑡𝑙),且𝐾和𝐿都能装入𝐼和𝐽。
我们要证明
𝐵𝑖 ∗ 𝑂𝑢𝑡𝑘 + 𝐵𝑗 ∗ 𝑂𝑢𝑡𝑙 > 𝐵𝑖 ∗ 𝑂𝑢𝑡𝑙 + 𝐵𝑗 ∗ 𝑂𝑢𝑡𝑘
𝐵𝑖 ∗ (𝑂𝑢𝑡𝑘 − 𝑂𝑢𝑡𝑙) + 𝐵𝑗 ∗ (𝑂𝑢𝑡𝑙 − 𝑂𝑢𝑡𝑘) > 0
(𝐵𝑖 − 𝐵𝑗) ∗ (𝑂𝑢𝑡𝑘 − 𝑂𝑢𝑡𝑙) > 0
以上每一步均可逆。
于是这样做可以保证答案最小。 对于找一个最大的可用的𝑂𝑢𝑡𝑗,可以用平衡树或者线段树完成。 时间复杂度(𝑁𝑙𝑜𝑔𝑁)。
接下来我们就要对于每一个从大到小的Bi,找出一个最大的能填进这个套娃的另一个套娃j。
方法一:权值线段树
我们将所以的Out放进权值线段树中,对于每一个Bi,查询小于当前套娃In[i]的最大的一个Out[j]的值,这一步就是查找权值线段树的前驱,然后找到后在那个权值的位置上删除就好了。时间复杂度O(n log n)
方法二:并查集
对于每一个权值i,我们先将它的father赋值为i-1,将所有出现过的Out的father赋值成它们自己,并且记录t[i]表示权值i出现的次数,那么直接查询In[i]-1的father即它的前一个最大的Out的值,然后将出现次数-1,如果次数为0,就将它的father赋值为i-1即可。
Code1
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define I int
#define ll long long
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define N 200010
using namespace std;
I n,f[N],ls[N],rs[N],tot,now,rt;
ll ans;
struct node{I x,y,z;}a[N];
inline I R(I &x){
x=0;char ch=getchar();for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);return x;
}
void cge(I &x,I l,I r,I k,I p){
if(!x) x=++tot;f[x]+=p;
if(l==r) return;
I M=l+r>>1;
if(k<=M) cge(ls[x],l,M,k,p);
else cge(rs[x],M+1,r,k,p);
}
I pre(I x,I l,I r,I k){
if(!f[x]) return 0;
if(l==r) return l;
I M=l+r>>1,t;
if(k<=M) return pre(ls[x],l,M,k);
else return (t=pre(rs[x],M+1,r,k))?t:pre(ls[x],l,M,k);
}
I cmp(node a,node b){return a.z>b.z;}
I main(){
freopen("doll.in","r",stdin);
freopen("doll.out","w",stdout);
R(n);
F(i,1,n){
R(a[i].x),R(a[i].y),R(a[i].z);
ans+=(ll)a[i].y*a[i].z;cge(rt,1,1e4,a[i].x,1);
}
sort(a+1,a+1+n,cmp);
F(i,1,n){
now=pre(1,1,1e4,a[i].y-1);
ans-=(ll)now*a[i].z;
if(now) cge(rt,1,1e4,now,-1);
}
printf("%lld\n",ans);
return 0;
}
Code2
#include<cstdio>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define N 200010
using namespace std;
I n,tot,now,f[N],t[N];
ll ans;
struct node{I x,y,z;}a[N];
inline I R(I &x){
x=0;char ch=getchar();for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);return x;
}
I cmp(node a,node b){return a.z>b.z;}
I get(I x){return f[x]==x?x:f[x]=get(f[x]);}
I main(){
freopen("doll.in","r",stdin);
freopen("doll.out","w",stdout);
R(n);
F(i,1,1e4) f[i]=i-1;
F(i,1,n){
R(a[i].x),R(a[i].y),R(a[i].z);
ans+=(ll)a[i].y*a[i].z;t[f[a[i].x]=a[i].x]++;
}
sort(a+1,a+1+n,cmp);
F(i,1,n){
now=get(a[i].y-1);
ans-=(ll)now*a[i].z;
if(now){if(--t[now]==0) f[now]=now-1;}
}
printf("%lld\n",ans);
return 0;
}