http://www.lydsy.com/JudgeOnline/problem.php?id=1049

题意:给一个长度为n的整数序列。把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。1. 询问最少需要改变多少个数。 2. 在1的条件下每个数改变的绝对值之和的最小值。(n<=35000, 数据随机)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } const int N=50005, oo=~0u>>2;
int a[N], n, b[N], g[N], pos[N], nxt[N], inext[N], f[N]; void init() {
for1(i, 1, n) g[i]=oo;
for1(i, 1, n) {
int k=upper_bound(g+1, g+1+i, b[i])-g;
f[i]=k;
g[k]=b[i];
nxt[i]=pos[k];
inext[i]=pos[k-1];
pos[k]=i;
}
}
ll ans[N], c[N];
void work() {
for1(i, 2, n) {
int p=inext[i], pos=1;
ans[i]=oo;
while(p) { if(b[i]>=b[p]) pos=p; p=nxt[p]; }
p=pos;
ll sum=0, mx=-oo; c[p]=0;
for1(j, p+1, i-1) c[j]=c[j-1]+(b[j]<b[i]?1:-1);
for3(j, i-1, p) {
if(b[j]<=b[i] && f[j]+1==f[i]) {
ans[i]=min(ans[i], ans[j]+sum);
ans[i]=min(ans[i], ans[j]+sum-(ll)(b[i]-b[j])*(mx-c[j]));
}
if(mx<c[j]) mx=c[j];
sum+=abs(b[i]-b[j]);
}
}
} int main() {
read(n); b[1]=-oo; ++n;
for1(i, 2, n) read(a[i]), b[i]=a[i]-i;
++n; b[n]=oo-n;
init();
work();
printf("%d\n%lld\n", n-f[n], ans[n]);
return 0;
}

  

又是一题神题啊。orz

首先第一个问很容易看出

f[i]=min{f[j]+1, a[i]-a[j]>=i-j}

设b[i]=a[i]-i

f[i]=min{f[j]+1, b[i]>=b[j]}

然后就是lis的log算法。。。。

第二个问,好神!!!

首先发现,如果有b[i]>=b[j]且f[i]==f[j]+1时,区间[j, i]中的点一定都是大于b[i]或者小于b[j],很显然吧。。

而我们要将[j, i]的点变成合法序列一定是存在一个点t,使得[j, t]变成b[j],[t+1, i]变成b[i]。(在原序列中就变成了a[j], a[j+1]=a[j]+1, a[j+2]=a[j]+2...这样)

如何证明?不会QAQ

试着证明一下:考虑最优点t,假设b[t]不变成b[j],而是变成b'[t]>b[j],且b'[t]<b[i]。那么因为原b[t]<b[j]或者b[t]>b[i],显然费用为b'[t]-b[t]>b[j]-b[t](当b[t]<b[j]时)b[t]-b'[t]>b[t]-b[i](当b[t]>b[i]时),得出b[j]<b'[t]<b[i]没有b'[t]=b[j]或=b[i]优,即证。

那么这样搞是n^3的,,,,,,,,,,,,,,

先试着搞成n^2。考虑当前转移点为i

我们首先找出离i最远的j,b[i]>=b[j]且f[i]==f[j]+1,那么所有的转移点都包含在区间[j, i]中。

考虑从i向左枚举至j,当前在k,此时假设现在将所有[k+1, i-1]的点全部变为b[i],那么当k是转移点时,我们需要得到最小值。

因为现在[k+1, i-1]全都是变成了b[i],那么假设要将其中的点变成b[j],显然:如果原b[x]>b[i],那么费用还需要+(b[i]-b[j]),如果原b[x]<b[i],那么费用就需要-(b[i]-b[j])。假设[k, i]中最优点t,[k+1, t]有y个比b[i]大的点,z个比b[i]小的点,那么需要变化的费用为:

sum-(b[i]-b[k])*z+(b[i]-b[k])*y=sum-(b[i]-b[k])*(z-y),而区间[j, i]中所有转移点k显然是b[k]单调不降的,所以b[i]-b[k]在单调不增的,所以目标变成最大化(z-y)。

所以考虑前缀和找出最大的差就行了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

那么问题变成n^2...

然后题目说。。。随机数据。。。。。。。。。。。。水过。

(还有注意一点是,如何快速找到j点,那么我们在lis时向所有转移点连边,然后快速找到即可,否则复杂度会更大)

【BZOJ】1049: [HAOI2006]数字序列(lis+特殊的技巧)的更多相关文章

  1. bzoj 1049 [HAOI2006]数字序列

    [bzoj1049][HAOI2006]数字序列 Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不 ...

  2. bzoj 1049: [HAOI2006]数字序列【dp+二分+瞎搞】

    第一问明显就是用b[i]=a[i]-i来做最长不下降子序列 然后第二问,对于一对f[i]=f[j]+1的(i,j),中间的数一定要改的,并且是等于b[i]或者b[j],我不会证,然后因为是随机数据,所 ...

  3. 【BZOJ 1049】 1049: [HAOI2006]数字序列 (LIS+动态规划)

    1049: [HAOI2006]数字序列 Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变 ...

  4. 1049: [HAOI2006]数字序列 - BZOJ

    Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大.Input 第一行包含一个数n ...

  5. 2021.12.06 P2501 [HAOI2006]数字序列(动态规划+LIS)

    2021.12.06 P2501 [HAOI2006]数字序列(动态规划+LIS) https://www.luogu.com.cn/problem/P2501 题意: 现在我们有一个长度为 n 的整 ...

  6. 洛谷 P2501 [HAOI2006]数字序列 解题报告

    P2501 [HAOI2006]数字序列 题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. ...

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

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

  8. [luogu2501 HAOI2006] 数字序列 (递推LIS)

    题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. 输入输出格式 输入格式: 第一行包含一个数 ...

  9. 【BZOJ1049】【Luogu P2501】 [HAOI2006]数字序列 DP,结论,LIS

    很有(\(bu\))质(\(hui\))量(\(xie\))的一个题目. 第一问:求最少改变几个数能把一个随机序列变成单调上升序列. \(Solution:\)似乎是一个结论?如果两个数\(A_i\) ...

随机推荐

  1. pip 直接安装tar.gz zip文件包 (windows linux mac 可用)

    在不能连接外网的机器上安装python的各种包,解压安装要人工输入多条命令: tar -zxvf Flask-WTF-0.10.0.tar.gz cd Flask-WTF-0.10.0 python ...

  2. iOS 保存CGRect,CGPoint到NSArray'的方法

    由于CGRect和CGPoint等对象是Struct,即结构体,不是继承于NSObject的,所以需要先用NSValue的方法,把他们转化成NSValue对象,之后就可以存入NSArray了! @in ...

  3. Intellj IDEA快捷键

    Alt+回车 导入包,自动修正 Ctrl+N   查找类 Ctrl+Shift+N 查找文件 Ctrl+Alt+L  格式化代码 Ctrl+Alt+O 优化导入的类和包 Alt+Insert 生成代码 ...

  4. QQ图片名字

    ﻩ并亲了你一下ﻩ大兔子҉҉大兔子҉҉҉҉҉҉҉҉

  5. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

  6. 使用Antlr实现简单的DSL

    为什么要使用DSL DSL是领域专用语言,常见的DSL有SQL,CSS,Shell等等,这些DSL语言有别于其他通用语言如:C++,Java,C#,DSL常在特殊的场景或领域中使用.如下图: 领域专用 ...

  7. Redis笔记(三)Redis的数据类型

    前面说过,Redis的一大特性是支持丰富的数据类型, 这为更多的应用场景提供了可能. Redis有五种数据类型,包括string,list,set,sorted set和hash,注意,Redis的数 ...

  8. C++查询网站

    1.C++外文api查询 http://www.cplusplus.com/ 2.https://isocpp.org/ 3.Juce学习 http://www.thinksaas.cn/favori ...

  9. 3.Factory Method 工厂方法模式(创建型模式)

    1.定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使得一个类的实例化延迟到子类. 2.实现代码如下: /// <summary> /// 工厂方 ...

  10. 【bzoj3343】教主的魔法 分块

    [bzoj3343]教主的魔法 2014年4月26日8092 Description 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了 ...