zoukankan      html  css  js  c++  java
  • CF457B Distributed Join

    原题链接

    题意简述

    给定数组 (a)(b),大小为 (n)(m),每次操作可以把 (a) 数组或 (b) 数组里的任意位置的数复制到任意其他位置,其代价为该位置的值。最后需要满足 (a) 数组的任意位置与 (b) 数组的任意位置都被复制到了同一个地方。求最小代价。

    题目分析

    考虑 (a) 数组的位置 (i)(b) 数组的位置 (j),要将这两个位置复制到同一个地方,有两种情况:

    1. 直接把 (a_i) 复制到 (b_j)(假设 (a_i leq b_j),反之同理)

    2. (a_i) 复制到另一个地方 (a_k),再把 (b_j) 复制到 (a_k)(也可以复制到 (b_k),同理)

    第二种情况看似代价更大一点,但实际上同时满足了 (b_j)(a_i)(a_k) 复制到同一地方的条件。

    于是考虑贪心。

    (sum_b)(b) 数组所有元素的和,(max_a)(a) 数组的最大值,(pos_a)(a) 数组中最大值的位置。

    假设将 (b) 数组的所有位置复制到 (a) 的所有位置上,因为 (b) 中每个数都要复制到 (a)(n) 次,所以总的操作代价是 (n imes sum_b)。当然这只用到了情况1,还没有用到情况2。

    在上面的情况下(b) 数组的所有位置都已经复制到了 (a_k) 上,那如果我们把 (a_i) 复制到 (a_k) 呢?那是不是 (b) 数组就不用了复制到 (a_i) 了,因为它们都在 (a_k) 上。这样的代价是 (a_i),但我们的总代价又减少了复制到 (a_i) 上的代价 (sum_b)。于是当 (a_i leq sum_b) 时,考虑用情况2。

    怎么取 (a_k) 呢?可以将 (k)(pos_a),即 (a_k)(max_a)。因为这样总代价肯定会更小一点。

    Q : 有没有可能可以先把 (a_i) 复制到 (b_j) 上,再把 (b_j) 复制到 (a_k) 上呢(即互相复制到对方数组上)?这样上面的做法就考虑不到这种情况了。

    A : 可能,但是这等价于第2种情况,代价也一样。

    Q : 为什么不能将 (a) 数组复制到 (b) 数组上呢?

    A : 同理,两种情况取 (min) 即可。

    于是就做完了。时间复杂度 (O(n)),绰绰有余。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    namespace my_std{
    	#define ll long long
    	#define pc putchar
    	#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
    	#define il inline
    	il ll read(){
    		ll sum=0,f=1;
    		char ch=0;
    		while(!isdigit(ch)){
    			if(ch=='-') f=-1;
    			ch=getchar();
    		}
    		while(isdigit(ch)){
    			sum=sum*10+(ch^48);
    			ch=getchar();
    		}
    		return sum*f;
    	}
    	il void write(ll x){
    		if(x<0){
    			x=-x;
    			pc('-');
    		}
    		if(x>9) write(x/10);
    		pc(x%10+'0');
    	}
    }
    using namespace my_std;
    ll n,m,a[100010],b[100010],maxa=0,posa,maxb=0,posb,suma=0,sumb=0,ans1=0,ans2=0;
    //maxa:最大值 posa:最大值的位置 suma:a 数组所有数的和 ans1:把 b 复制到 a 的最小代价 
    int main(){
    	n=read();
    	m=read();
    	fr(i,1,n){
    		a[i]=read();
    		suma+=a[i];
    		if(a[i]>maxa){
    			maxa=a[i];
    			posa=i;
    		}
    	}
    	fr(i,1,m){
    		b[i]=read();
    		sumb+=b[i];
    		if(b[i]>maxb){
    			maxb=b[i];
    			posb=i;
    		}
    	}
    	fr(i,1,n){//分类讨论
    		if(i==posa) ans1+=sumb;//如果 i 已经是最大值的位置了,就不用复制到自己 
    		else if(a[i]<=sumb) ans1+=a[i];
    		else ans1+=sumb;
    	}
    	fr(i,1,m){//同理 
    		if(i==posb) ans2+=suma;
    		else if(b[i]<=suma) ans2+=b[i];
    		else ans2+=suma;
    	}
    	write(min(ans1,ans2));//取最小值 
    }
    
  • 相关阅读:
    主席树学习记录
    P1072 Hanson 的趣味题 题解
    好文章收集
    计算几何专题
    小问题
    CSP-S2020题解
    上下界网络流
    想到的无法解决的点子
    省选联考2020组合数问题
    省选数学复习
  • 原文地址:https://www.cnblogs.com/LZY-LZY/p/15239871.html
Copyright © 2011-2022 走看看