1. 程式人生 > 實用技巧 >Codeforces Round #555 (Div. 3) E. Minimum Array (貪心,二分,set)

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;
    }