HDU 6546 ( 贪心 )
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6546
题意:有n个二次函数,给每个函数选择一个值x,让所选x值的和正好等于m,问此时f(x)的最小值是多少。
思路:为了满足最小值的要求,我们先假设所有函数就选择 -b/(2*a) 的最小值点,然后我们看一下这样选择后是比m大还是小,如果小,我们就让所选的pos增加,是必然的答案也会增加,所以我们需要选择n个函数里增幅最小的那个。用优先队列维护。
优化:注意到所选x必须是正整数,所以我们就全初始化为1。这样我们就只需要维护增加的部分,减小的部分就不用维护了。
注意:以后做题还是要想好再开始写代码,不然找bug真的太绝望了。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node {
int a,b,c;
int pos;
}f[100005];
struct nod {
int a,b,c,pos,id;
int want;
}up;
bool operator<( const nod &a, const nod &b )
{
return a.want>b.want;
}
int n,m,sum;
priority_queue<nod> Qu;
signed main()
{
cin >> n >> m;
sum = 0;
while ( !Qu.empty() ) Qu.pop();
for ( int i=0; i<n; i++ ) {
scanf("%lld %lld %lld",&f[i].a,&f[i].b,&f[i].c);
f[i].pos = 1;
sum += f[i].pos;
up.a=f[i].a;up.b=f[i].b;up.c=f[i].c;up.pos=f[i].pos;up.id=i;up.want=0;
up.want = up.a*(up.pos+1)*(up.pos+1) + up.b*(up.pos+1) + up.c;
up.want -= (up.a*(up.pos)*(up.pos) + up.b*(up.pos) + up.c);
Qu.push(up);
}
while ( sum<m && !Qu.empty() ) {
up = Qu.top(); Qu.pop();
up.pos++; sum++;
f[up.id].pos ++;
up.want = 0;
up.want = up.a*(up.pos+1)*(up.pos+1) + up.b*(up.pos+1) + up.c;
up.want -= (up.a*(up.pos)*(up.pos) + up.b*(up.pos) + up.c);
Qu.push(up);
}
int ans = 0;
for ( int i=0; i<n; i++ ) {
ans += ( f[i].a*f[i].pos*f[i].pos + f[i].b*f[i].pos + f[i].c );
}
cout << ans << endl;
return 0;
}