[ARC085F] NRE

[ARC085F] NRE

首先这道题要先将区间按左端点排序

\(f_i\) 表示前 \(i\) 个区间已经决策好是否选择,而且\(i\) 个区间必选的情况下的最小不同数。再令 \(sum_i\) 表示前 \(i\) 个数中 \(1\) 的个数。枚举一个区间 \(j<i\),可以根据区间 \([l_j,r_j],[l_i,r_i]\) 二者是否有交集来进行分类讨论。这里我们记初始的 \(f_0\) 的答案为全 \(0\) 数组与 \(b\) 的不同数。

  • 被包含,即 \(r_i\le r_j\),这种情况下直接略过。(可以转移,但是贡献还是 \(f_j\),没什么用)。

  • 二者没有交集,那么就是 \(f_i=\min{f_j-(sum_{r_i}-sum_{l_i-1})+[(r_i-l_i+1)-(sum_{r_i}-sum_{l_i-1})]}\),原因是本来 \(1\) 的位置和 \(0\) 不同有贡献,现在没有了,即前面加的一坨,而本来 \(0\) 的位置贡献是 \(0\) 的,现在变为 \(+1\)。化简一下就是 \(f_i=\min{f_j-2(sum_{r_i}-sum_{l_i-1})+r_i-l_i+1}\)。(\(r_j<l_i\)

  • 二者有交集,那就相当于增加了 \([r_j+1,r_i]\) 这一部分。将上面的式子改为 \(f_i=\min{f_j-2(sum_{r_i}-sum_{r_j})+r_i-r_j}\)

这样一个 \(O(N^2)\) 暴力就出炉了。

接下来考虑怎么优化它。

它这些区间,发现范围都跟 \(r_j\) 是挂钩的。所以以 \(r_j\) 为下标似乎是个好主意。

  1. \(r_i\le r_j\) 这种情况不管。
  2. 没有交集的可以以 \([r_j,f_j]\) 插入到线段树/树状数组中,然后直接一个区间查询 \([0,l_i-1]\) 的最小值。
  3. 有交集的可以先提炼出关于 \(j\) 的式子,插入 \([r_j,f_j+2sum_{r_j}-r_j]\) 即可,查询 \([l_i,r_i-1]\) 的最小值。
  4. 当然插入操作是在计算完 \(f_j\) 之后进行的。
  5. 注意,\(r_j\) 可能存在相等的情况,插入时注意要取 \(\min\) 而不是直接赋值(被这里坑了)。

这样复杂度就是 \(O(N\log N)\)

对于 5 的 hack 数据

5
1 1 1 1 1 
5
4 4
2 3
2 5
2 4
1 4

数据生成

#include <any>
#include <cstdio>
#include <random>
#include <ctime>
using namespace std;
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
const int N=5,Q=5;
random_device rnd;
mt19937 rd(rnd());
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","w",stdout);
    // freopen("1.out","w",stdout);
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    #endif
    // Insert Code Here
    printf("%d\n",N);
    E(i, N)printf("%d ",rd()&1);
    printf("\n%d\n",Q);
    E(i, N){
        int l=rd()%N+1;
        int r=rd()%N+1;
        if(l>r)swap(l, r);
        printf("%d %d\n",l,r);
    }
    return 0;
}

对拍参考代码来自的是洛谷这篇题解

错误代码

正确代码

posted @ 2023-06-04 20:56  wscqwq  阅读(13)  评论(0编辑  收藏  举报