CF335F 思维难题 题解
题目传送门
题目大意
现有
解题思路
部分思路参考这篇题解,但由于这篇题解讲的不是很到位,于是想再作一些补充,并提供一种较为清晰,循序渐进的解题思路。
先将所有物品按价格从大到小排序,对于每件物品,考虑它是否要白嫖,然后发现对一件物品白嫖与否只与其价值大小有关,所有可以将价值相同的物品分入一组,按组考虑。
对于第
一开始可以无脑白嫖的数量是
然后考虑剩下的
此时问题就转变成了,我们怎么对堆顶物品进行“撤销”操作了。原先,我们是买了某件价格为
最后堆里面留下的物品的价值之和就是可以白嫖的钱辣!
感觉这题的难点其实在理解两个式子中的
Code
#include<bits/stdc++.h>
#define int long long
#define forr(i,l,r) for(register int i=l;i<=r;i++)
#define ffor(i,r,l) for(register int i=r;i>=l;i--)
using namespace std;
const int N=5e5+10;
int a[N],b[N],c[N],d[N];
priority_queue<int,vector<int>,greater<int> > q;
bool cmp(int q,int p)
{
return q>p;
}
signed main()
{
ios::sync_with_stdio(0);
int n;
cin>>n;
int ans=0,c1=0;
forr(i,1,n)
{
cin>>a[i];
ans+=a[i];
}
sort(a+1,a+n+1,cmp);
forr(i,1,n)
{
if(i==1||a[i]!=a[i-1])
{
b[++c1]=a[i];
}
c[c1]++;
}
int p=0,c2=0,c3=0,x,y;
forr(i,1,c1)
{
c3=0;
p=min(c2-2*(int)q.size(),c[i]);
forr(j,1,p)
{
d[++c3]=b[i];
}
p=min(c2,c[i])-p;
forr(j,1,p)
{
x=q.top();
if(x<b[i])
{
d[++c3]=b[i];
if(p>j)
{
d[++c3]=b[i];
}
}
else
{
d[++c3]=x;
y=2*b[i]-x;
if(j<p&&y>0)
{
d[++c3]=y;
}
}
q.pop();
j++;
}
forr(j,1,c3)
{
q.push(d[j]);
}
c2+=c[i];
}
while(!q.empty())
{
ans-=q.top();
q.pop();
}
cout<<ans<<endl;
return 0;
}
最后能不能不要脸地讨个赞啊