首页 > 其他分享 >P4331 [BalticOI 2004] Sequence 数字序列

P4331 [BalticOI 2004] Sequence 数字序列

时间:2023-12-19 19:46:04浏览次数:32  
标签:分段 Sequence int 函数 min pos 2004 BalticOI define

[BalticOI 2004] Sequence 数字序列

Luogu P4331

题目描述

给定一个整数序列 \(a_1, a_2, \cdots , a_n\),求出一个递增序列 \(b_1 < b_2 < ··· < b_n\),使得序列 \(a_i\) 和 \(b_i\) 的各项之差的绝对值之和 \(|a_1 - b_1| + |a_2 - b_2| + \cdots + |a_n - b_n|\) 最小。

【数据范围】

  • \(40\%\) 的数据 \(n≤5000\);
  • \(60\%\) 的数据 \(n≤300000\);
  • \(100\%\) 的数据 \(n≤10^6 , 0≤a_i≤2^{31}-1\);

Solution

Slope trick 入门题。

先将所有 \(a_i\) 对应减去 \(i\),要求的限制从单调上升变为单调不降。那么有一个显然的 DP:设 \(f(i,j)\) 表示第 \(i\) 个位置的值 \(\le j\) 的最小代价,那么有转移:

\[f(i,j)\gets \min\{f(i-1,j)+|j-a_i|,f(i,j-1)\} \]

直接做是 \(\mathcal O(n^2)\) 的,考虑优化。

将 \(f(i,j)\) 看成分段函数 \(g_i(j)\),容易发现这个函数是下凸的。考虑将 \(j\) 看作自变量,那么设 \(h_i(j)=|j-a_i|\),那么转移可以看作是 \(f_{i-1}(j)\) 整体加上分段函数 \(h_i(j)=|j-a_i|\),然后再取一个前缀 \(\min\)。

设计一种方式来表示分段函数。使用分段函数的第一段和一个可重集来表示分段函数,其中可重集中的元素 \(x\) 表示当前分段函数在 \(x\) 处斜率 \(+1\)。如 \(f(x)=|x|\) 可以表示成为 \(f(x)=-x,\{0,0\}\)。

那么本题中的转移可以看作是加上了 \(g(j)=a_i-j,\{a_i,a_i\}\)。两个分段函数相加,直接将斜率相加,拐点直接取并集即可。

使用优先队列维护这个下凸壳的所有拐点,因为转移是取 \(\min\),因此需要关心这个分段函数中斜率为 \(0\) 的那条线段。具体做法就是分开维护两个优先队列,\(L\) 中存储在 \(0\) 线段左侧的拐点,\(R\) 中存储在 \(0\) 线段右侧的拐点,设初始斜率为 \(K\),那么只需要维护 \(K+\text{size}(L)=0\) 即可。本题中需要用到取前缀 \(\min\) 的操作,所以只需要保留 \(L\) 即可。

对于方案的输出,可以在转移的时候记录决策点,然后倒推出方案。

时间复杂度 \(\mathcal O(n\log n)\)。

Code
// Cirno is not baka!
#include <bits/stdc++.h>
using namespace std;
#ifdef CIRNO
#include <debug.hpp>
#else
#define Debug(...)
#endif
#define For(i, a, b) for (int i = (a); i <= (int)(b); ++i)
#define Rof(i, a, b) for (int i = (a); i >= (int)(b); --i)
#define All(x) x.begin(), x.end()
#define pii pair<int, int>
#define fi first
#define se second
#define i64 long long
#define mkp make_pair
#define int long long
#define epb emplace_back

const int _N = 1e6 + 5, mod = 1e9 + 7, inf = 1e9;
template<typename T> void Max(T &x, T y) {x = max(x, y);}
template<typename T> void Min(T &x, T y) {x = min(x, y);}

namespace BakaCirno {
    int N, A[_N], pos[_N];
    priority_queue<int> q;
    void _() {
        cin >> N;
        For(i, 1, N) cin >> A[i], A[i] -= i;
        int K = 0;
        For(i, 1, N) {
            K += -1;
            q.emplace(A[i]), q.emplace(A[i]);
            while (K + q.size() != 0) q.pop();
            pos[i] = q.top();
        }
        Rof(i, N - 1, 1) Min(pos[i], pos[i + 1]);
        int ans = 0;
        For(i, 1, N) ans += abs(A[i] - pos[i]);
        cout << ans << '\n';
        For(i, 1, N) cout << pos[i] + i << ' ';
        cout << '\n';
    }
}

void File(const string file) {
    freopen((file + ".in").c_str(), "r", stdin);
    freopen((file + ".out").c_str(), "w", stdout);
}
signed main() {
    // File("");
    cin.tie(0)->sync_with_stdio(0); int T = 1;
    // cin >> T;
    while (T--) BakaCirno::_();
}

标签:分段,Sequence,int,函数,min,pos,2004,BalticOI,define
From: https://www.cnblogs.com/hanx16msgr/p/17914518.html

相关文章

  • [Ynoi2004] rpmtdq 题解
    人生第一发\(Ynoi\)的题,写一篇题解庆祝一下传送门我们可以发现,对于二元组\((x,y)\),若存在一个\(dist(i,j)\ledist(x,y),x<i<j<y\)那么答案肯定不是二元组\((x,y)\)我们可以考虑把这些肯定不是的点剔除掉考虑怎么找,我们可以先点分治,求出每个点......
  • [ARC133B] Dividing Subsequence
    DividingSubsequence这道题与最长公共子序列类似,可以先去水一水那道题。题意本题就是让你从\(p\)里面选出一个子序列\(b_i\)和\(q\)里面选出一个子序列\(a_i\),我们要使\(b_i\)是\(a_i\)的倍数。解法本题直接用动态规划,是\(O(n^2)\)做法,会超时,因此我们用树状数......
  • [AGC049D] Convex Sequence 题解
    题目链接点击打开链接题目解法好题!!考虑原题的限制相当于原序列下凸,即差分数组单调考虑把原序列在第一个最小值处割成\(2\)半因为原序列是凸的,所以非最小值的长度是\(\sqrt{2m}\)级别的这可以让我们\(dp\)差分数组,即求满足\(\sum\limits_{i=1}^{n'}ib_i=m'\)的\(b......
  • dict( [1,2] ) # TypeError: cannot convert dictionary update sequence element
    dict([1,2])#TypeError:cannotconvertdictionaryupdatesequenceelement#0toasequence#listtupleset都可以,并且list(list([1,2]))==[1,2]#仍然是[1,2]list({"key":"value"})#只保留键名......
  • [CF83E] Two Subsequences 题解
    [CF83E]TwoSubsequences题解思路定义\(overlap(a,b)\)为字符串\(a\)的后缀与\(b\)的前缀的最大相等的长度,有\(|f(a,b)|=|a|+|b|-overlap(a,b)\),下文称匹配为相邻两串的\(overlap\)。观察到每次操作之后,一定有一个序列是以\(a_i\)为结尾的。所以根据这个......
  • LncDLSM: Identification of Long Non-coding RNAs with Deep Learning-based Sequenc
    关键词:作者:期刊:IEEEJournalofBiomedicalandHealthInformatics年份:2023论文原文:https://doi.org/10.1101/2022.09.02.506180主要内容1问题:长链非编码RNA(LncRNAs)在调控基因表达和其他生物过程中起着至关重要的作用。区分lncRNA和蛋白质编码转录本(PCTs)有助于研究人员深......
  • D2. Xor-Subsequence (hard version)
    D2.Xor-Subsequence(hardversion)Itisthehardversionoftheproblem.Theonlydifferenceisthatinthisversion$a_i\le10^9$.Youaregivenanarrayof$n$integers$a_0,a_1,a_2,\ldotsa_{n-1}$.Bryapwantstofindthelongestbeautifulsub......
  • P1090 [NOI洛谷P2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
    可以用堆来实现,或者更简单一点的优先队列优先队列:#include<queue>priority_queue<int,vector<int>,greater<int>>q;因为每次合并后,最小的两个值都会更新,所以可以很好的利用优先队列内元素有序的特点,减少因反复排序带来的时间复杂度;一开始我用STL自带的排序sort,报了5个TLE,后来意......
  • P1090 [NOIP2004 提高组] 合并果子
    原题链接题解每次从所有果子堆中选重量最小的两堆并累加,观察到只需要找出最小因此考虑用堆代码#include<bits/stdc++.h>usingnamespacestd;intpile[10005]={0};intlen=0;voidin(intx){pile[++len]=x;intnow=len;while(pile[now]<pile[now/2]......
  • linux Centos 8.2.2004 安装Apache
    Apache服务器安装步骤1.下载安装包至安装目录,wgethttps://mirrors.aliyun.com/apache/httpd/http-2.4.58.tar.bz22.在安装目录下解压文件 tar -xjvf http-2.4.58.tar.bz23.进入解压目录安装文件  3.1进入解压目录cdhttp-2.4.58.tar.bz2  3.2安装文件yuminsta......