Codeforces1157E. Minimum Array

題目http://codeforces.com/contest/1157/problem/E

題意:給定整數型n,a與b數組長度均爲n,其中的a與b中的每個元素大小爲0<= a[i] (或者b[i]) <n,現在可以改變b數組的元素順序,用現在的b數組與a數組做如下操作:

          c[i] = ( a[i] + b[i] ) % n

          最後操作完之後的c數組要保證字典序最小。輸出這樣的c數組

 

思路:因爲是模操作並且元素的數據範圍容易讓我們想到這裏面的模操作會形成閉環。比如n=5,當前a=2,那麼b=0,1,2,3,4對應的結果爲2,3,4,0,1形成了閉環。並且這樣的環不會重疊,畢竟a與b的數據範圍在這裏放着。這裏n-a=3是最優的答案,那麼如果找不到這樣的剛剛好的答案怎麼選擇? 

          lower_bound(n-a)找到是距離現在n-a最近的點,但是會有一個疑問在n-a有左右兩種選擇,我們究竟是向左選擇還是向右選擇?顯然lower_bound(n-a)是向右貪心選擇的,怎麼才能排除左邊的點呢?

         這裏有兩種情況,如果b數組中沒有一個數大於等於n-a,那麼是不是理解爲此時的lower_bound找到的是end()?此時最優的就是左數第一個元素最優咯。第二種情況,lower_bound能夠找到,設當前找到的元素爲find,那麼我們就是比較(find+a)%n與(a+b[0])%n的大小,因爲find+a>n但是一定是小於2n的,所以(find+a)%n = find+a-n,發現什麼了嗎?find+a-n<a<=a+b[0],所以此時的向右找到的第一個值一定是對的。

 

AC code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;

int n;
int a[maxn],b[maxn];
multiset<int>res;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i]);
        res.insert(b[i]);
    }

    for(int i=1;i<=n;i++)
    {
        int tmp=n-a[i];
        auto findd=res.lower_bound(tmp);
        if(findd==res.end())
            findd=res.begin();
        int ans=*findd;
        res.erase(findd);
        printf("%d%c",(ans+a[i])%n,i==n?'\n':' ');
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章