CF297C Splitting the Uniqueness 题解

CF297C Splitting the Uniqueness 题解

非常好构造题,使我的草稿纸旋转。

解法

我们记输入的数组为 a a a,需要输出的两个数组为 b , c b,c b,c(因为当时起变量名起的)。

考虑利用 a i a_i ai 互不相同的性质。

先将 a i a_i ai 升序排序。因为题中保证 a i a_i ai 互不相同,所以相邻两数的差至少为 1 1 1,从而 a i ≥ i − 1 a_i \ge i - 1 aii1

考虑到最多有 ⌈ n 3 ⌉ \lceil \dfrac{n}{3} \rceil 3n 个重复数字,即为需要至少有 ⌊ 2 n 3 ⌋ \lfloor \dfrac{2n}{3} \rfloor 32n 种不同数字。我们可以将整个数组等分为 3 3 3 段,分别是 [ 1 , ⌊ n 3 ⌋ ] [1,\lfloor \dfrac{n}{3} \rfloor ] [1,3n⌋] ( ⌊ n 3 ⌋ , ⌊ 2 n 3 ⌋ ] (\lfloor \dfrac{n}{3} \rfloor,\lfloor \dfrac{2n}{3} \rfloor] (⌊3n,32n⌋] ( ⌊ 2 n 3 ⌋ , n ] (\lfloor \dfrac{2n}{3} \rfloor,n] (⌊32n,n]。具体构造如下图。

图片

为什么这么构造是对的?

显然对于 c c c 数组,第二段和第三段的数互不相同,满足至少有 ⌊ 2 n 3 ⌋ \lfloor \dfrac{2n}{3} \rfloor 32n 种不同数字。考虑为什么 b b b 数组至少有 ⌊ 2 n 3 ⌋ \lfloor \dfrac{2n}{3} \rfloor 32n 种不同数字。

观察第一段和第三段,因为 a i ≥ i − 1 a_i \ge i-1 aii1,所以第三段的第一个 a i a_i ai 满足 a i ≥ 2 n 3 a_i \ge \dfrac{2n}{3} ai32n,而 n − ⌊ 2 n 3 ⌋ − 1 = ⌈ n 3 ⌉ − 1 n - \lfloor \dfrac{2n}{3} \rfloor -1 = \lceil \dfrac{n}{3} \rceil - 1 n32n1=3n1,所以 c i c_i ci 满足 c i ≥ n 3 c_i \ge \dfrac{n}{3} ci3n,而在第三段 a a a 单调上升, c c c 单调下降,所以 b b b 单调上升,所以 b b b 数组在第一段和第三段互不相同。

代码

#include<bits/stdc++.h>
namespace fast_IO
{
    /**
     * 没啥用的快读快写
    */
};
using namespace fast_IO;
int n,b[100010],c[100010],fir,sec;
struct node
{
    int val,ord;
    inline bool operator<(const node rhs) const
    {
        return val<rhs.val;
    }
};
node a[100010];
int main()
{
    in>>n,fir=n/3,sec=n*2/3;
    for(int i=1;i<=n;i++) in>>a[i].val,a[i].ord=i;
    std::sort(a+1,a+n+1);
    for(int i=1;i<=fir;i++) b[a[i].ord]=i-1,c[a[i].ord]=a[i].val-b[a[i].ord];
    for(int i=fir+1;i<=sec;i++) c[a[i].ord]=i-1,b[a[i].ord]=a[i].val-c[a[i].ord];
    for(int i=n;i>sec;i--) c[a[i].ord]=n-i,b[a[i].ord]=a[i].val-c[a[i].ord];
    out<<"YES\n";
    for(int i=1;i<=n;i++) out<<b[i]<<' ';
    out<<'\n';
    for(int i=1;i<=n;i++) out<<c[i]<<' ';
    fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
    return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值