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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值