令$a'_{i}=a_{i}+n-i$、$b'_{i}=b_{i}+n-i$,代价仍然是$\sum_{i=1}^{n}|a'_{i}-b'_{i}|$,但条件变为了$b'_{i}\le b'_{i+1}$,即不下降(以下为了方便,$a'_{i}$和$b'_{i}$仍然用$a_{i}$和$b_{i}$表示,原来的不需要考虑)

考虑暴力dp,令$f_{i,j}$表示前$i$个数且$b_{i}=j$的最小的代价,转移时先令$f_{i-1,j}=\min_{k\le j}f_{i-1,k}$,再加上绝对值,即$f_{i,j}=f_{i-1,j}+|a_{i}-j|$

由于过程是交替进行的,可以看作先加上绝对值再取min(体现在定义上就是$f_{i,j}$表示前$i$个数且$b_{i}\le j$的最小的代价),细节上由于第1次全部都是0本身就不需要取min,然后最后答案即为$f_{n,\infty}$

归纳$f_{i}$具有以下性质:其斜率单调不递增且小于等于0(即下凸但没有上升的部分)

在这一条件下,对于取绝对值再取min的过程,可以看作:对于$a_{i}$左半部分相当于斜率增加1,对于$a_{i}$右半部分斜率减少1,特别的,由于要取min,因此对于斜率为0的部分仍然不变

(做法上有一点类似[AGC049E](https://www.cnblogs.com/PYWBKTDA/p/14015313.html))

定义$f'_{i,j}=f_{i,j}-f_{i,j-1}$($j\ge 1$),特别的$f'_{i,0}=\sum_{j=1}^{i}a_{i}$,那么$f_{i,j}=\sum_{k=0}^{j}f'_{i,k}$(其实后面两点不重要,因为求答案肯定通过构造出来的方案求更方便QAQ)

然后对于$f'_{i,j}$($1\le j\le a_{i}$)区间减1,对于$f'_{i,j}$($a_{i}<j$且$f'_{i,j}<0$)区间加1,直接用线段树维护即可

关于最优解的构造:先有$b_{n}=\min_{f'_{n,k}=0}k$,然后再令$b_{i}=\min(b_{i+1},\min_{f'_{i,k}=0}k-1)$即可(很明显$b_{i+1}$之前$f_{i,j}$最小的位置就是这里,同时这里的$f_{i,j}$不会是跟$f_{i,j-1}$取min的结果)

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1000005
  4. 4 #define L (k<<1)
  5. 5 #define R (L+1)
  6. 6 #define mid (l+r>>1)
  7. 7 map<int,int>mat;
  8. 8 map<int,int>::iterator it;
  9. 9 int n,m,a[N],b[N],val[N],f[N<<2],tag[N<<2];
  10. 10 long long ans;
  11. 11 char ch[21];
  12. 12 int read(){
  13. 13 int x=0;
  14. 14 char c=getchar();
  15. 15 while ((c<'0')||(c>'9'))c=getchar();
  16. 16 while (('0'<=c)&&(c<='9')){
  17. 17 x=x*10+c-'0';
  18. 18 c=getchar();
  19. 19 }
  20. 20 return x;
  21. 21 }
  22. 22 void write(int k){
  23. 23 int s=0;
  24. 24 while (k){
  25. 25 ch[++s]=k%10+'0';
  26. 26 k/=10;
  27. 27 }
  28. 28 while (s)putchar(ch[s--]);
  29. 29 putchar(' ');
  30. 30 }
  31. 31 void upd(int k,int x){
  32. 32 tag[k]+=x;
  33. 33 f[k]+=x;
  34. 34 }
  35. 35 void down(int k){
  36. 36 upd(L,tag[k]);
  37. 37 upd(R,tag[k]);
  38. 38 tag[k]=0;
  39. 39 }
  40. 40 void update(int k,int l,int r,int x,int y,int z){
  41. 41 if ((l>y)||(x>r))return;
  42. 42 if ((x<=l)&&(r<=y)){
  43. 43 upd(k,z);
  44. 44 return;
  45. 45 }
  46. 46 down(k);
  47. 47 update(L,l,mid,x,y,z);
  48. 48 update(R,mid+1,r,x,y,z);
  49. 49 f[k]=min(f[L],f[R]);
  50. 50 }
  51. 51 int query(int k,int l,int r){
  52. 52 if (l==r)return l;
  53. 53 down(k);
  54. 54 if (f[R])return query(R,mid+1,r);
  55. 55 return query(L,l,mid);
  56. 56 }
  57. 57 int main(){
  58. 58 scanf("%d",&n);
  59. 59 for(int i=1;i<=n;i++)a[i]=read()+n-i;
  60. 60 memcpy(val,a,sizeof(val));
  61. 61 sort(val+1,val+n+1);
  62. 62 m=unique(val+1,val+n+1)-val-1;
  63. 63 for(int i=1;i<=n;i++)a[i]=lower_bound(val+1,val+m+1,a[i])-val;
  64. 64 for(int i=1;i<=n;i++){
  65. 65 update(1,1,m,1,a[i],-1);
  66. 66 if (i>1)update(1,1,m,a[i]+1,query(1,1,m),1);
  67. 67 b[i]=query(1,1,m);
  68. 68 }
  69. 69 for(int i=n-1;i;i--)b[i]=min(b[i],b[i+1]);
  70. 70 for(int i=1;i<=n;i++)ans+=abs(val[a[i]]-val[b[i]]);
  71. 71 printf("%lld\n",ans);
  72. 72 for(int i=1;i<=n;i++)write(val[b[i]]-n+i);
  73. 73 }

[luogu4331]数字序列的更多相关文章

  1. 找出数组中最长的连续数字序列(JavaScript实现)

    原始题目: 给定一个无序的整数序列, 找最长的连续数字序列. 例如: 给定[100, 4, 200, 1, 3, 2], 最长的连续数字序列是[1, 2, 3, 4]. 小菜给出的解法: functi ...

  2. 九度OJ 1544 数字序列区间最小值

    题目地址:http://ac.jobdu.com/problem.php?pid=1544 题目描述: 给定一个数字序列,查询任意给定区间内数字的最小值. 输入: 输入包含多组测试用例,每组测试用例的 ...

  3. 【BZOJ】【1049】【HAOI2006】数字序列

    DP 第一问比较水……a[i]-=i 以后就变成最长不下降子序列问题了,第二问这个结论好神奇,考试的时候怎么破?大胆猜想,不用证明?TAT 题解:http://pan.baidu.com/share/ ...

  4. kaggle之数字序列预测

    数字序列预测 Github地址 Kaggle地址 # -*- coding: UTF-8 -*- %matplotlib inline import pandas as pd import strin ...

  5. string 数字序列大小比较

    string 数字序列大小比较 string.compare string a = "022"; string b="1"; 比较结果 '022' < ' ...

  6. codevs 2622 数字序列

    2622 数字序列 提交地址:http://codevs.cn/problem/2622/  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold     题目描述 De ...

  7. Shell生成数字序列

    转自http://kodango.com/generate-number-sequence-in-shell Shell里怎么输出指定的数字序列: for i in {1..5}; do echo $ ...

  8. 《剑指offer》第四十四题(数字序列中某一位的数字)

    // 面试题44:数字序列中某一位的数字 // 题目:数字以0123456789101112131415…的格式序列化到一个字符序列中.在这 // 个序列中,第5位(从0开始计数)是5,第13位是1, ...

  9. 【BZOJ1049】 [HAOI2006]数字序列

    BZOJ1049 [HAOI2006]数字序列 dp好题? 第一问 第一问我会做!令\(b_i=a_i-i\),求一个最长不下降子序列. \(n-ans\)就是最终的答案. 第二问 好难啊.不会.挖坑 ...

随机推荐

  1. 题解 「HDU6403」卡片游戏

    link Description 桌面上摊开着一些卡牌,这是她平时很爱玩的一个游戏.如今卡牌还在,她却不在我身边.不知不觉,我翻开了卡牌,回忆起了当时一起玩卡牌的那段时间. 每张卡牌的正面与反面都各有 ...

  2. Vue3学习(二)之集成Ant Design Vue

    一.集成Ant Design Vue npm install ant-design-vue@2.0.0-rc.3 --save 兼容性 Ant Design Vue 2.x 支持所有的现代浏览器. 如 ...

  3. C# 三种方式实现Socket数据接收(经典)

    Stream.Read 方法 当在派生类中重写时,从当前流读取字节序列,并将此流中的位置提升读取的字节数. 语法: public abstract int Read(byte[] buffer, in ...

  4. Apache Shiro漏洞绕过waf小tips

    看了篇文章觉得不错记录下以免以后找不到,原理是通过base64解码特性导致waf不能成功解码绕过waf检测从而进行攻击 解码情况: payload php python openresty java ...

  5. [no code][scrum meeting] Alpha 8

    项目 内容 会议时间 2020-04-14 会议主题 API文档第一版交付 会议时长 30min 参会人员 PM+OCR组成员 $( "#cnblogs_post_body" ). ...

  6. 2021.9.25考试总结[NOIP模拟61]

    终于有点阳间题了然而挂了60pts 哈哈 T1 交通 类似简单题,限制看似很复杂,但不难发现当确定一条边是否被删后会产生裙带关系,很多边会跟着自动被确定是否被删. 仔细观察可以得出这种关系会构成偶环结 ...

  7. 如何理解Stand SPI Dual SPI 和Quad SPI??

    1.首先看一下接口 Standard SPI: CLK, /CS, DI, DO, /WP, /Hold Dual SPI: CLK, /CS, IO0, IO1, /WP, /Hold Quad S ...

  8. 零基础学习Linux心得总结

    很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...

  9. distinct-subsequences leetcode C++

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  10. Python 模块 itertools

    python 2.6 引入了itertools模块,使得排列组合的实现非常简单: import itertools 有序排列:e.g., 4个数内选2个排列: >>> print l ...