cf1607G. Banquet Preparations 1(贪心逼近答案)

13 篇文章 2 订阅
8 篇文章 1 订阅

传送门

题意

给定 n n n 道菜,第 i i i 道菜中含有 a i a_i ai a a a 型原材料和 b i b_i bi b b b 型原材料。现在需要从每道菜中必须吃掉 m m m 份原材料,求最终 a a a 型原材料总份数与 b b b 型原材料总份数绝对值之差的最小值,以及达成该最小值的过程中,每道菜的吃法。

考虑开始时直接优先吃 a a a 型原材料,若在该情况下,最终 s u m a ≥ s u m b suma ≥ sumb sumasumb,则一定不可能更优, s u m a − s u m b suma-sumb sumasumb 即为答案。

而当 s u m a < s u m b suma<sumb suma<sumb 时,可求 t e m p = ( s u m b − s u m a ) / 2 temp=(sumb-suma)/2 temp=(sumbsuma)/2,则若能使得发生 s u m a + t e m p suma+temp suma+temp s u m b − t e m p sumb-temp sumbtemp 变化,则可得到最优解。

由此重新对 n n n 道菜进行遍历,并判断其中能从吃 a a a 型转化为吃 b b b 型的最大值,从而逐渐减少 t e m p temp temp 值。当 t e m p = 0 temp=0 temp=0 时则得到最优解。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=2e5+10;

int n,m;
int a[N],b[N];
int l[N],r[N];

void solve(){
    cin>>n>>m;
    int sum1=0,sum2=0;
    for(int i=1;i<=n;i++){
    	cin>>a[i]>>b[i];
    	l[i]=a[i]-m;
    	r[i]=b[i];
    	if(l[i]<0)
    		r[i]+=l[i],l[i]=0;
		sum1+=l[i];
		sum2+=r[i];
	}
	if(sum1>=sum2){
		cout<<sum1-sum2<<endl;
		for(int i=1;i<=n;i++){
			cout<<a[i]-l[i]<<" "<<b[i]-r[i]<<endl;
		}
		return ;
	}
    int temp=(sum2-sum1)/2;
    for(int i=1;i<=n;i++){
        if(temp==0)
			break;
        int x=min(a[i]-l[i],r[i]);
        x=min(x,temp);
        temp-=x;
        l[i]+=x;
        r[i]-=x;
    }
    int ans=0;
	for(int i=1;i<=n;i++)
		ans=ans+l[i]-r[i];
	cout<<abs(ans)<<endl;
	for(int i=1;i<=n;i++){
		cout<<a[i]-l[i]<<" "<<b[i]-r[i]<<endl;
	}
}

signed main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t;
    cin >> t;
    while(t--)
        solve();
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值