【题】【(堆/线段树/树状数组优化DP)/图论】NKOJ 3485 数据

来源:互联网 发布:java特种兵 编辑:程序博客网 时间:2024/04/29 16:41

NKOJ 3485 数据
时间限制 : 30000 MS 空间限制 : 165536 KB

问题描述
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。

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

样例输入
【样例输入1】
4
1 9 3 2

【样例输入2】
10
4 4 3 5 0 -4 -2 -1 3 5

样例输出
【样例输出1】
2

【样例输出2】
3

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

来源 【2015多校联训4】 by YZ

法一,图论:
因为a[i]>=0时,i可以无损耗到达i+a[i]+1号节点,所以连一条权值为0单向边,注意终点可能超过n+1号,也是合法的。
因为一个节点到达k号后,往左或往右一格均视为操作一次,所以各个节点向左右连一条双向边,注意包括超过n+1的点。且第一个点与第二个点不连。
若a[1]<0 ,则至少需要 -a[i]的操作数,所以强行将a[1]改为0,并答案强制加-a[1]。
最后找出1到n+1的最短路

/*图论*/#include<cstdio>#include<queue> #include<vector>#include<iostream>using namespace std;const int need=110003;const int inf=1e9; int n,nn;//.....................................inline void in_(int &d){    char t=getchar();bool mark=false;    while(t<'0'||t>'9') {if(t=='-') mark=true;t=getchar();}    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';    if(mark) d=-d;}//.....................................struct bian{    int la,en,len;};vector<bian> w;#define pb(a,b,c) push_back((bian){a,b,c})int tot,fi[need];void add(const int &a,const int &b,const int &c){    tot++;    w.pb(fi[a],b,c);    fi[a]=tot;} //.....................................int s,e;struct fy{    int dis,id;    bool operator< (const fy &b) const    {        return dis>b.dis;    }};priority_queue<fy> q;#define pu(a,b) push((fy){a,b}) bool getans[need];int dis[need];void dijkstra(int s){    for(int i=1;i<=nn;i++) dis[i]=inf,getans[i]=false;    q.pu(0,s),dis[s]=0;    int x,y,t;    while(!q.empty())    {        while(!q.empty()&&getans[q.top().id]) q.pop();        x=q.top().id;        if(x==e) return ;        getans[x]=true;        q.pop();        for(t=fi[x];t;t=w[t].la)        {            y=w[t].en;            if(getans[y]) continue;            if(dis[y]>dis[x]+w[t].len)            {                dis[y]=dis[x]+w[t].len;                q.pu(dis[y],y);            }        }    }}//.....................................int main(){    w.resize(1);    int n;scanf("%d",&n);    int dans=0;    int a;    in_(a);    if(a<0) dans=-a,add(1,2,0);    else add(1,a+2,0);    nn=max(nn,a+2);    for(int i=2,a;i<=n;i++)     {        in_(a);        if(a>=0) add(i,i+a+1,0);        nn=max(nn,i+a+1);        add(i,i+1,1),add(i+1,i,1);    }    for(int i=n+1;i<=nn;i++) add(i,i+1,1),add(i+1,i,1);    s=1,e=n+1;    dijkstra(s);    cout<<dis[e]+dans;}

法二-1:堆优化动规

#include<cstdio>#include<set>#include<iostream>#include<queue>using namespace std;const int need=100003;const int inf=1e9;int a[need];int f[need];struct fy{    int val,key;    friend bool operator< (const fy a,const fy &b)     {        //if(a.val==b.val) return a.key<b.key;        return a.val>b.val;    }};priority_queue<fy> q1;#define pu(a,b) push((fy){a,b}) int q2=inf;//............................................inline void in_(int &d){    char t=getchar();bool mark=false;    while(t<'0'||t>'9') {if(t=='-') mark=true;t=getchar();}    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';    if(mark) d=-d;}//............................................int main(){    int n;scanf("%d",&n);    for(int i=1;i<=n;i++) in_(a[i]);    q1.pu(a[1]+1,a[1]+1);    for(int i=1;i<=n;i++)     {    //cout<<q1.top().key;        while(!q1.empty()&&q1.top().key<=i)         {            q2=min(q1.top().val-2*q1.top().key,q2);            q1.pop();            //cout<<q1.size();        }        f[i]=q2+i;        if(!q1.empty()) f[i]=min(f[i],q1.top().val-i);        q1.pu(f[i]+a[i+1]+i+1,a[i+1]+i+1);    }    cout<<f[n];}
0 0
原创粉丝点击