返回顶部

Codeforces Round #555 (Div. 3) E. Minimum Array (贪心,二分,set)

  • 题意:给你两个长度为\(n\)的数组\(a\)\(b\),元素值在\([0,n-1]\),可以对\(b\)数组的元素任意排序,求新数组\(c\),满足\(c_i=(a_i+b_i)\ mod\ n\),并且使得其字典序最小.

  • 题解:这种取模求最小的题,我们一眼就能看出最优情况一定是\(b_i=n-a_i\),可以先用set存一下\(b\)中的元素,然后在set中二分找\(\ge \ n-a_i\)的值,因为\(a_i\)加上一个比\(n-a_i\)小的数再取模一定\(\ge a_i\),但是加上\([n-a_i,n-1]\)中的数一定再取模的范围在\([0,a_i-1]\),因为加上\(n-a_i\)取模的值是\(0\),而\([n-a_i,n-1]\)中有\(a_i\)个数,所以这样贪心一定正确的,假如set没有比\(n-a_i\)大的数,那么我们取集合中的第一个元素一定是最优的.

  • 代码:

    int n;
    int a[N];
    int x;
    set<int> s;
    map<int,int> mp;
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n;
    
        rep(i,1,n) cin>>a[i];
        rep(i,1,n){
        	cin>>x;
        	mp[x]++;
        	s.insert(x);
        }
    
        s.insert(n);
    
        rep(i,1,n){
        	if(a[i]==0) a[i]=n;
        	auto cur=s.lower_bound(n-a[i]);
    
        	if(*cur==n){ 
        		int now=*s.begin();
        		cout<<(now+a[i])%n<<' ';
        		mp[now]--;
        		if(mp[now]==0) s.erase(now);
        		continue;
        	}
    
        	cout<<(*cur+a[i])%n<<' ';
        	mp[*cur]--;
        	if(mp[*cur]==0) s.erase(*cur);
        }
    
        return 0;
    }
    
posted @ 2020-11-18 11:35  Rayotaku  阅读(73)  评论(0编辑  收藏  举报