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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮