贪心—有时是对的 ---qzezoj 1532: ZCC Loves Codefires

题面传送门
贪心一般和排序逃不开关系。这一道题目是普及组原题的弱化版。
首先我们列出答案的式子 a n s = ∑ i = 1 n ( a i × ∑ j = 1 i b j ) ans=\sum\limits_{i=1}^{n}{(a_i\times\sum\limits_{j=1}^{i}{b_j})} ans=i=1n(ai×j=1ibj)
乘法分配律, a n s = ∑ i = 1 n ( a i × b i + a i × ∑ j = 1 i − 1 b j ) ans=\sum\limits_{i=1}^{n}{(a_i\times b_i+a_i\times \sum\limits_{j=1}^{i-1}{b_j})} ans=i=1n(ai×bi+ai×j=1i1bj)
分配到每一个 s i s_i si,得 s i = a i × b i + a i × ∑ j = 1 i − 1 b j s_i=a_i\times b_i+a_i\times \sum\limits_{j=1}^{i-1}{b_j} si=ai×bi+ai×j=1i1bj
若要比较两个 a x a_x ax a y a_y ay的优先级关系,得 a x × b x + a x × ∑ j = 1 x − 1 b j + a y × b y + a y × ∑ j = 1 y − 1 b j < a y × b y + a y × ∑ j = 1 y − 1 b j + a x × b x + a x × ∑ j = 1 x − 1 b j a_x\times b_x+a_x\times \sum\limits_{j=1}^{x-1}{b_j}+a_y\times b_y+a_y\times \sum\limits_{j=1}^{y-1}{b_j}<a_y\times b_y+a_y\times \sum\limits_{j=1}^{y-1}{b_j}+a_x\times b_x+a_x\times \sum\limits_{j=1}^{x-1}{b_j} ax×bx+ax×j=1x1bj+ay×by+ay×j=1y1bj<ay×by+ay×j=1y1bj+ax×bx+ax×j=1x1bj
两边同时消去,得 a x × ∑ j = 1 x − 1 b j + a y × ∑ j y − 1 b j < a y × ∑ j = 1 y − 1 b j + a x × ∑ j x − 1 b j a_x \times \sum\limits_{j=1}^{x-1}{b_j}+a_y\times \sum\limits_{j}^{y-1}{b_j}<a_y \times \sum\limits_{j=1}^{y-1}{b_j}+a_x\times \sum\limits_{j}^{x-1}{b_j} ax×j=1x1bj+ay×jy1bj<ay×j=1y1bj+ax×jx1bj
再由于 y = x + 1 y=x+1 y=x+1,进行乘法分配律拆解,得 a y × b x < a x × b y a_y\times b_x<a_x\times b_y ay×bx<ax×by
所以一个排序函数就可以得到答案了。
代码实现

#include<cstdio>
#include<algorithm>
using namespace std;
int n;
struct yyy{
int x,y;
}s[100039];
inline bool cmp(yyy x,yyy y){
return x.x*y.y<y.x*x.y;
}
long long ans,tot;
int main(){
register int i;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&s[i].x);
for(i=1;i<=n;i++) scanf("%d",&s[i].y);
sort(s+1,s+n+1,cmp);
for(i=1;i<=n;i++){
ans+=s[i].x;
tot+=ans*s[i].y;
}
printf("%lld",tot);
return 0;
}

不过瘾?再来看一道
呵呵, 一看就是田忌赛马呀,只不过做两遍罢了。那么我们直接看代码…(笑)
首先如何让得分最大化。
回想一下田忌赛马,预备赛马的应该是一个有序组。所以我们先排一个序,满足
i < j < k i<j<k i<j<k, a i ≥ a j ≥ a k a_i\geq a_j\geq a_k aiajak.
然后应该考虑最强的两匹马。分类讨论。
命题一:若我方最强的马可以干掉对方最强的马,则直接干。
命题二:若我方最弱的马可以干掉对方最弱的马,则直接干
命题三:若命题一命题二都不成立,那么直接让我方最弱的马送给对方最强的马。
但在命题三中,我方最弱的马可能与对方最弱的马打平。所以要特判。
我方最低分则以对手最高分减去总分就可以了。
代码实现:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a[100039],b[100039],ra,rb,la,lb,ans,flag;
int main() {
register int i;
scanf("%d",&n);
for(i=1; i<=n; i++) scanf("%d",&a[i]);
for(i=1; i<=n; i++) scanf("%d",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
ra=rb=n;
la=lb=1;
for(i=1; i<=n; i++) {
if(a[ra]>b[rb])ra--,rb--,ans+=2;
else if(a[la]>b[lb])lb++,la++,ans+=2;
else {
if(a[la]==b[rb]) la++,rb--,ans++;
else la++,rb--; } }
printf("%d ",ans);
ra=rb=n;
la=lb=1;
ans=0;
for(i=1; i<=n; i++) {
if(a[ra]<b[rb])ra--,rb--,ans+=2;
else if(a[la]<b[lb])lb++,la++,ans+=2;
else {
if(a[ra]==b[lb]) lb++,ra--,ans++;
else lb++,ra--; } }
printf("%d",2*n-ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值