数据--dp,线段树优化

题目描述
Mr_H 出了一道信息学竞赛题,就是给 n 个数排序。输入格式是这样的:试题有若干组数据。每组数据的第一个是一个整数 n,表示总共有 n 个数待排序;接下来 n 个整数,分别表示这 n 个待排序的数。
例如:3 4 2 –1 4 1 2 3 4,就表示有两组数据。第一组有 3 个数(4,2,-1),第二组有 4个数(1,2,3,4)。可是现在 Mr_H 做的输入数据出了一些问题。例如:2 1 9 3 2 按理说第一组数据有 2 个数(1,9),第二组数据有 3 个数,可是“3”后面并没有出现三个数,只出现了一个数“2”而已!
现在 Mr_H 需要对数据进行修改,改动中“一步”的含义是对文件中的某一个数+1 或-1,写个程序,计算最少需要多少步才能将数据改得合法。

输入
第一行一个整数 m,表示 Mr_H 做的输入数据包含的整数个数。第二行包含 m 个整数 a[i],每个整数的绝对值不超过 10000。

输出
一个整数,表示把数据修改为合法的情况下,最少需要多少步。

样例输入
4
1 9 3 2

样例输出
2

提示
对于 20%的数据,m<=10, |a[i]|<=5;
对于 60%的数据,m<=5000, |a[i]|<=10000
对于 100%的数据,m<=100000, |a[i]|<=10000

容易想到f[i]:a[1]-a[i]合法最小的步数,f[i]=min{f[k]+|i-(k+1)-a[k]|}。时间复杂度为O(n^2)
如果从后往前考虑,f[j]:a[j]-a[n]合法的最小步数,f[j]=min{f[k]+| (a[j]+j+1) -k|}.
分类讨论:
(1).(a[j]+j+1)>=j ,f[j]=min{f[k]-k} + (a[j]+j+1));
(2).(a[j]+j+1)

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define INF 2000000000

struct node{
    int l,r,minf[3];
}tree[MAXN*4+100];
int n,a[MAXN+10],f[MAXN+10];
//f[i]:a[i]~a[n]改合法要用的最小步数

void read()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
}
void build(int i,int l,int r)
{
    tree[i].l=l,tree[i].r=r;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
}
void insert(int i,int pos,int d,int flag)
{
    if(tree[i].l==pos && tree[i].r==pos){
        tree[i].minf[flag]=d;
        return ;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    if(pos<=mid) insert(i*2,pos,d,flag);
    else insert(i*2+1,pos,d,flag);

    tree[i].minf[flag]=min(tree[i*2].minf[flag],tree[i*2+1].minf[flag]);
}
int Quary(int i,int l,int r,int flag)
{
    if(r<tree[i].l || tree[i].r<l) return INF;
    if(l<=tree[i].l && tree[i].r<=r){
        return tree[i].minf[flag];
    }
    int x=Quary(i*2,l,r,flag);
    int y=Quary(i*2+1,l,r,flag);
    return min(x,y);
}
void dp()
{
    insert(1,n+1,-(n+1),1);
    insert(1,n+1,n+1,2);
    for(int i=n;i>=1;i--){
        int tmp=a[i]+i+1,x=-1,y=-1;
        if(tmp<i+1)
            y=Quary(1,i+1,n+1,2),f[i]=y-tmp;
        else if(tmp+1<=n+1){
            x=Quary(1,i+1,tmp,1);
            y=Quary(1,tmp+1,n+1,2);
            f[i]=min(x+tmp,y-tmp);
        }
        else
            x=Quary(1,i+1,n+1,1),f[i]=x+tmp;
        //特别注意这里的范围
        insert(1,i,f[i]-i,1);
        insert(1,i,f[i]+i,2);
    }
}
int main()
{
    read();
    build(1,1,n+1);
    dp();
    printf("%d\n",f[1]);
    return 0;
}
posted @ 2015-10-11 08:53  KatarinaYuan  阅读(181)  评论(0编辑  收藏  举报