您的位置:首页 > 其它

【BZOJ 1049】 [HAOI2006]数字序列

2015-02-25 11:33 337 查看

1049: [HAOI2006]数字序列

Time Limit: 10 Sec Memory Limit: 162 MB

Submit: 979 Solved: 389

[Submit][Status]

Description

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

Input

第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。

Output

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

Sample Input

4

5 2 3 5

Sample Output

1

4

HINT

【数据范围】

90%的数据n<=6000。

100%的数据n<=35000。

保证所有数列是随机的。

神奇的dp。

对于第一问:

改变的数最少即让不变的数最多,那么类似于求最长上升子序列,只是要求增加:f[i]=max(f[j]+1) (a[i]-a[j]>=i-j)

把a[i]-a[j]>=i-j移项:

a[i]-i>=a[j]-j

因此把每一个数都减去i,直接求LIS即可(用nlogn的算法)

对于第二问(注意:此时每个数已经减去i了!!):

我们要求使得a数组单调不减的最少改变量。

ydc题解

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define M 35005
#define LL long long
using namespace std;
LL g[M],s1[M],s2[M];
struct edge
{
int y,ne;
}e[M];
int m[M],cnt,h[M],a[M],n,f[M];
void read(int &tmp)
{
tmp=0;
char ch=getchar();
int fu=1;
for (;ch<'0'||ch>'9';ch=getchar())
if (ch=='-') fu=-1;
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=tmp*10+ch-'0';
tmp*=fu;
}
void Solve1()
{
memset(m,127,sizeof(m));
int ma=1;
m[1]=a[1],f[1]=1;
for (int i=2;i<=n;i++)
{
int l=1,r=ma,ans=0;
while (l<=r)
{
int mid=(l+r)>>1;
if (m[mid]<=a[i]) ans=mid,l=mid+1;
else r=mid-1;
}
f[i]=ans+1;
ma=max(ma,f[i]);
m[f[i]]=min(m[f[i]],a[i]);
}
printf("%d\n",n-f
);
}
void Insert(int x,int y)
{
e[++cnt].y=y;
e[cnt].ne=h[x];
h[x]=cnt;
}
void Solve2()
{
for (int i=n;i>=0;i--)
{
Insert(f[i],i);
g[i]=1LL<<60;
}
g[0]=0,a[0]=-1<<30;
for (int i=1;i<=n;i++)
for (int j=h[f[i]-1];j;j=e[j].ne)
{
int p=e[j].y;
if (p>i) break;
if (a[p]>a[i]) continue;
for (int k=p;k<=i;k++)
s1[k]=abs(a[p]-a[k]),s2[k]=abs(a[i]-a[k]);
for (int k=p+1;k<=i;k++)
s1[k]+=s1[k-1],s2[k]+=s2[k-1];
for (int k=p;k<i;k++)
g[i]=min(g[i],g[p]+s1[k]-s1[p]+s2[i]-s2[k]);
}
cout<<g
<<endl;
}
int main()
{
read(n);
for (int i=1;i<=n;i++)
read(a[i]),a[i]-=i;
a[++n]=1<<30;
Solve1();
Solve2();
return 0;
}




感悟:

1.WA无数次:第一问求错,求整个序列的最长不下降序列,我直接把f
当做答案了,应该再加一句a[++n]=inf,f
才是答案

2.第二问是贪心,发现贪心似乎都是用反证法来证明的。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: