BZOJ1049 [HAOI2006]数字序列0

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

Description

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

Input

  第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。n<=35000,保证所有数列是随机的

Output

  第一行一个整数表示最少需要改变多少个数。 第二行一个整数,表示在改变的数最少的情况下,每个数改变
的绝对值之和的最小值。

Sample Input

4

5 2 3 5

Sample Output

1

4

正解:DP

解题报告:

  考虑补集转换,题目转换为:最大化不修改的点。

  对于任意的i,j(j<i),如果可以通过修改中间的j-i+1个数来使得[j,i]满足要求,必要条件是a[i]-a[j]>=i-j,不妨设b[i]=a[i]-i,则条件变为b[i]>=b[j],至此第一问最长不降子序列可做。

  第二问,不妨设g[i]为1到i的答案,则

  $${g[i]=min(g[j]+cost[j+1,i])}$$

  j需要满足:j可以转移到i且$${f[j]+1=f[i]}$$

  cost[j,i]表示修改[j,i]的最小代价

  结论:必定存在点t使得[j,t]都为bj,[t+1,i]都为bi。证明从略

  只需每次找到一个分割点,暴力枚举即可。细节较多。

 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <string>
10 using namespace std;
11 typedef long long LL;
12 const int MAXN = 35011;
13 const LL inf = (1LL<<50);
14 int n;
15 LL a[MAXN],g[MAXN],cost1[MAXN],cost2[MAXN],b[MAXN],c[MAXN],ans,f[MAXN];
16 vector<int>w[MAXN];
17 inline int getint(){
18     int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar();
19     if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w;
20 }
21 inline int find(LL x){ int l=1,r=n,pos=0,mid; while(l<=r) { mid=(l+r)>>1; if(c[mid]<=x) l=mid+1,pos=mid; else r=mid-1; } return pos; }
22 inline void work(){
23     n=getint(); for(int i=1;i<=n;i++) a[i]=getint(),b[i]=a[i]-i; a[++n]=inf; b[n]=a[n]-n; for(int i=1;i<=n;i++) c[i]=g[i]=inf;
24     for(int i=1;i<=n;i++) f[i]=find(b[i])+1,c[f[i]]=min(c[f[i]],b[i]); for(int i=1;i<=n;i++) ans=max(ans,f[i]);
25     printf("%lld\n",n-ans); w[0].push_back(0); int from; LL now; b[0]=-inf;//!!!
26     for(int i=1;i<=n;i++) {
27         from=f[i]-1;
28         for(int j=0,size=w[from].size();j<size;j++) {
29             int v=w[from][j]; if(b[i]<b[v]) continue;//转移不到
30             cost1[v-1]=cost2[v-1]=0;
31             for(int k=v;k<=i;k++) cost1[k]=abs(b[k]-b[v]),cost2[k]=abs(b[k]-b[i]);
32             for(int k=v+1;k<=i;k++) cost1[k]+=cost1[k-1],cost2[k]+=cost2[k-1];
33             for(int k=v;k<=i;k++) {
34                 now=cost1[k]-cost1[v]+cost2[i]-cost2[k];
35                 g[i]=min(g[i],g[v]+now);
36             }
37         }
38         w[f[i]].push_back(i);
39     }
40     printf("%lld",g[n]);
41 }
42
43 int main()
44 {
45     work();
46     return 0;
47 }
时间: 2024-08-27 07:06:01

BZOJ1049 [HAOI2006]数字序列0的相关文章

BZOJ1049: [HAOI2006]数字序列

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1049 题解: ydc的题解:http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411 第二问比较神?考场上敢去猜结论? 代码: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring&g

【BZOJ 1049】 [HAOI2006]数字序列

1049: [HAOI2006]数字序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 979  Solved: 389 [Submit][Status] Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. Output 第一行一个整数表示最少需要改变多少

【BZOJ】1049: [HAOI2006]数字序列(lis+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=1049 又是一题神题啊.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],

[HAOI2006]数字序列

题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. 输入输出格式 输入格式: 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. 输出格式: 第一行一个整数表示最少需要改变多少个数. 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值. 输入输出样例 输入样例#1: 复制 4 5 2 3 5 输出样例#1: 复制 1 4 说明 [数据范围] 90%的数据n<=

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

题目描述 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. 输入输出格式 输入格式: 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. 输出格式: 第一行一个整数表示最少需要改变多少个数. 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值. 输入输出样例 输入样例#1: 4 5 2 3 5 输出样例#1: 1 4 说明 [数据范围] 90%的数据n<=6000.

[HAOI2006] 数字序列 - dp,二分

现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大.求在改变的数最少的情况下,每个数改变的绝对值之和的最小值. \(n\leq 35000\),保证数据随机 Solution 第一问很容易,只需要令 \(b_i=a_i-i\),然后跑最长不下降子序列即可 下面考虑第二问,令 \(f[i]\) 表示前 \(i\) 个数构成的数列要变成单调上升需要改动的最小幅度 若 \(a_i,a_j, i<j\) 满足

p2501 [HAOI2006]数字序列

传送门 分析 https://www.luogu.org/blog/FlierKing/solution-p2501 对于第二问的感性理解就是有上下两条线,一些点在上面的线的上面或者下面的线的下面,然后看它们变成哪个线的位置更优 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<ccty

【bzoj1049】【HAOI2006】【数字序列】

1049: [HAOI2006]数字序列 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1117 Solved: 454 [Submit][Status][Discuss] Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. Output 第一行一个整数表示

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

DP 第一问比较水……a[i]-=i 以后就变成最长不下降子序列问题了,第二问这个结论好神奇,考试的时候怎么破?大胆猜想,不用证明?TAT 题解:http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411 没有将a[0]置为-INF在BZOJ上WA了……so sad…… 1 /************************************************************** 2 Problem: 10