首页 > 其他分享 >CF467E 题解

CF467E 题解

时间:2024-07-25 17:40:35浏览次数:12  
标签:nxt CF467E rs int 题解 mid color ans

题面

给出这种限制,我们只能 4 个 4 个考虑。令 \(f_i\) 为考虑到 \(a_i\),最长的 \(b\) 序列长 \(4f_i\)。

令 \(mx_i\) 为以 \(a_i\) 结尾的最短连续子序列包含 \(x\ y\ x\ y\) 的(不一定连续的)结构的左端点。

于是有 \(f_i=\max_{j=1}^{mx_i-1} f_j+4\)。

用前缀和优化:

\(g_i=\max_{j=1}^if_j\)。

\(f_i=g_{mx_i-1}+4\)。

dp 的时间复杂度变为 \(O(n)\)。

考虑如何求出 \(mx_i\)。

注意到如果把 \(x\) 和 \(y\) 都列出来,形如 \(\color{white}\cdots {x}\color{blue}{y}\color{green}{y}\color{white}{x}\color{red}{y}\color{white}y\cdots\),那么这一组 \(xyxy\) 的左端点固定,右端点最左也会在 \(\color{red} y\) 上,而如果存在 \(\color{white}{x}\color{blue}{y}\color{white}{x}\color{red}{y}\) ,则一定存在 \(\color{white}{x}\color{green}{y}\color{white}{x}\color{red}{y}\)。

也就是 \(r_i\) 的最优结构中一定存在这样的一种结构:两个 \(y\) 之间一定没有其他 \(y\)。

这时问题变为对于相邻两个同颜色的位置 \(l,r\) 求最大的 \(i\in [1,l)\) 使得 \(\exists j\in(l,r) \text{ s.t. }a_i=a_j\)。

这是可持久化线段树的板子题:

令 \(nxt_i\) 为最小的满足 \(a_i=a_j,j>i\) 的 \(j\)。不存在即为 \(n+1\)。

然后按照 \(nxt_i\) 排序,在 \(rt_{nxt_i}\) 时插入到 \(i\) 的位置。

对于 \(l,r\):\(mx_i\) 即为 \(rt_{l+1}\) 到 \(rt_r\) 中存在值的最大下标,可以线段树上二分 \(O(\log n)\) 解决。

当然还有一种情况:\(y=x\)。

当然这是容易的,此时 \(mx_{nxt^3_i}\xleftarrow{\text{getmax}} i\)。我们记 \(nxt^k_x=nxt_{nxt^{k-1}_x},nxt^0_x=x\)。

总复杂度 \(O(n\log n)\)。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 5e5 + 5;
int n, a[N];

int rt[N];
struct sgt
{
    int a[N << 5], ls[N << 5], rs[N << 5], idx;
    void upd(int q, int l, int r, int x, int &u, int v)
    {
        u = ++idx;
        a[u] = a[x], ls[u] = ls[x], rs[u] = rs[x];
        if(l == r) return a[u] += v, void();
        int mid = l + r >> 1;
        if(mid >= q) upd(q, l, mid, ls[x], ls[u], v);
        else upd(q, mid + 1, r, rs[x], rs[u], v);
        a[u] = a[ls[u]] + a[rs[u]];
    }
    int fnd2(int l, int r, int x, int y)
    {
        if(l == r) return l;
        int mid = l + r >> 1;
        if(a[rs[x]] - a[rs[y]]) return fnd2(mid + 1, r, rs[x], rs[y]);
        return fnd2(l, mid, ls[x], ls[y]);
    }
    int fnd(int ql, int qr, int l, int r, int x, int y)
    {
        if(ql > qr || ql > r || qr < l) return -1;
        if(ql <= l && r <= qr)
        {
            if(a[x] == a[y]) return -1;
            return fnd2(l, r, x, y);
        }
        int mid = l + r >> 1, ans;
        if((ans = fnd(ql, qr, mid + 1, r, rs[x], rs[y])) == -1)
            return fnd(ql, qr, l, mid, ls[x], ls[y]);
        return ans;
    }
}t;

int nxt[N], now[N];
int b[N], h = 0;

void init()
{
    memcpy(b, a, sizeof b);
    sort(b + 1, b + n + 1);
    h = unique(b + 1, b + n + 1) - b - 1;
    for(int i = 1; i <= n; i ++)
        a[i] = lower_bound(b + 1, b + h + 1, a[i]) - b;

    for(int i = n; i >= 1; i --)
        if(!now[a[i]])
        {
            now[a[i]] = i;
            nxt[i] = n + 1;
        }
        else
        {
            nxt[i] = now[a[i]];
            now[a[i]] = i;
        }
    struct node {int id, p;} c[N];
    for(int i = 1; i <= n; i ++) 
        c[i] = {i, nxt[i]};
    sort(c + 1, c + n + 1, [](auto &x, auto &y) {return x.p < y.p;});
    for(int i = 1, j = 1; i <= n && c[i].p <= n; i ++)
    {
        while(j < c[i].p) rt[j] = rt[j - 1], j ++;
        t.upd(c[i].id, 1, n, rt[j - 1], rt[j], 1);
        j ++;
    }
}

int u[N], v[N], f[N], g[N], fr[N], id[N];
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i]; 
    init();
    for(int i = 1; i <= n; i ++)
    {
        if(!now[i]) continue;
        int p = 0;
        for(int r = nxt[now[i]], l = now[i]; r != n + 1; l = r, r = nxt[r], p = nxt[p])
        {
            int ans = t.fnd(1, l - 1, 1, n, rt[r - 1], rt[l]);
            if(r == nxt[nxt[nxt[now[i]]]]) p = now[i];
            if(ans != -1)
                u[r] = ans, v[r] = r;
            if(p && u[r] < p)
                v[r] = r, u[r] = p;
        }
    }
    for(int i = 1; i <= n; i ++)
    {
        if(u[i] < u[i - 1])
            u[i] = u[i - 1], v[i] = v[i - 1];
        if(u[i])
        {
            f[i] = g[u[i] - 1] + 4;
            fr[i] = id[u[i] - 1];
        }
        if(f[i] > g[i - 1])
            g[i] = f[i], id[i] = i;
        else g[i] = g[i - 1], id[i] = id[i - 1];
    }
    cout << g[n] << "\n";
    vector<int> ans;
    for(int i = id[n]; i; i = fr[i])
    {
        ans.push_back(b[a[v[i]]]);
        ans.push_back(b[a[u[i]]]);
        ans.push_back(b[a[v[i]]]);
        ans.push_back(b[a[u[i]]]);
    }
    reverse(ans.begin(), ans.end());
    for(int i : ans) cout << i << " ";

    return 0;
}

标签:nxt,CF467E,rs,int,题解,mid,color,ans
From: https://www.cnblogs.com/adam01/p/18323792

相关文章

  • CF594A 题解
    题面来个不一样的证明。根据样例,我们可以有一个直觉:两点之间一定距离\(\fracn2\),答案为这样的点对之间\(\Deltax\)的最小值。直接交上去,发现这是对的。为什么呢?先证明上界:先手可以让答案小于等于两点距离\(\fracn2\)点对的\(\Deltax\)的最小值。这是容易的:先手只......
  • 题解:Codeforces Round 961 (Div. 2) B1&B2
    本题含有B1和B2两个难度版本。由于关系相近,我把他们放在同一篇博客中,可自行选择观看B1.Bouquet(EasyVersion)timelimitpertest:1.5secondsmemorylimitpertest:512megabytesinput:standardinputoutput:standardoutputThisistheeasyversionoftheprobl......
  • CF568C New Language 题解
    Description将\(\texttt{a}\sim\texttt{a}+l-1\)这\(l\)个字符分成\(\texttt{V,C}\)两个集合。你需要构造一个长度为\(n\)且满足\(m\)个限制且不小于另一个长度为\(n\)的字符串\(s\)的最小字符串。每一个限制为若字符串的第\(p_1\)个位置上的字符\(\in......
  • CF22E 题解
    题面注意到题目给的图为基环树森林。因为一个(\(n>1\))的强连通图每个点都要有出度和入度,所以:对于每个基环树,叶子结点是没有入度的,所以一定要有一条从环上出发的路径经过这个点。对于基环树的环,注意到它缩点后没有出度,所以一定要有一条出边。注意到叶子结点的需求和根节点相反,......
  • 题解:AT_arc116_e [ARC116E] Spread of Information
    题目链接思路看到最大值最小首先可以想到二分,发现答案具有单调性,那么思考如何在\(O(n)\)的时间内判断是否合法。考虑贪心,在最远没覆盖的点的距离和要判断的\(mid\)刚好相等的时侯再选择一定不劣,因为这样覆盖的点最多,那么从叶子节点向上回溯,处理它的所有儿子,判断是否选择该......
  • LG3107 [USACO14OPEN] Odometer S 题解 (数位DP+容斥)
    题意定义一个数是神奇的当且仅当这个数中有一个数位出现了一半及以上,比如112,2233。求\([l,r]\)中有多少个好的数字,\(100\lel,r\le10^{18}\)。题解考虑数位DP,先把答案转为\(Ans(r)-Ans(l-1)\),我们钦定一个数\(k\)让他必须出现多于一半,然后我们想求\([1,x]\)中有多少......
  • CF1015F 题解
    题面考虑这样的匹配问题,可以想如何确定第一次匹配,这样可以不重不漏地计数。考虑dp的时候同时维护有几个括号没有匹配,匹配到\(s\)的第几位,所以令\(f(i,j,k)\)表示dp到(要计数的序列的)第\(i\)个字符,有\(j\)个左括号没有匹配,匹配到\(s\)的第\(k\)位。转移很容易,考......
  • 程序设计:C++入门教程(速成) + 15道经典例题(附带例题解析)
    本文章以实用为主,若实在是不明白文字所表达的内容,无脑复制代码,自己动手运行一下,实验一下即可理解文章内容,放心,代码是全的,全选复制粘贴即可不废话,直接开整数据类型常用数据类型int:整数类型,用于表示整数值。例如:1,2,-3,0等。float:单精度浮点数类型,用于表示带有小数点的数......
  • AT_arc116_e [ARC116E] Spread of Information 题解
    题目传送门前置知识二分答案|树形DP解法答案显然具有单调性,考虑二分答案。设当前二分出的答案为\(mid\),则等价于覆盖距离为\(mid\)的情况下进行选点。做法同luoguP3942将军令,考虑进行贪心,对于深度最深的叶节点将选择的点放在边界时,即取\(mid\)级祖先时,覆盖的范......
  • 题解—[ABC265E] Warp
    题面简单计数DP。由于数据范围很大,所以状态不能常规设置为\(dp_{i,j}\)。注意到\(n\)只有\(300\),考虑设\(dp_{i,j,k}\)表示三种行走方法分别使用\(i\),\(j\),\(k\)次的路径数量。状态转移很简单,先计算出来当前所在位置,如果是障碍就跳过,否则$dp_{i,j,k}=dp_{i-1,j,k}+dp......