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

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];
}
排序算法 快速排序 ⭐⭐⭐⭐ 归并排序 ⭐⭐⭐ 桶排序 ⭐⭐(特殊场景) 注:冒泡/选择/插入排序极少直接考察,但需理解原理 搜索算法 DFS/BFS ⭐⭐⭐⭐⭐(90%比赛必考) 记忆化搜索 ⭐⭐⭐⭐(DP优化常用) 剪枝技巧 ⭐⭐⭐(DFS优化) 动态规划 一维普通DP(爬楼梯/打家劫舍类) ⭐⭐⭐⭐ 背包DP01背包/完全背包) ⭐⭐⭐ 树形DP(最近公共祖先相关) ⭐⭐ 数据结构 栈(表达式计算/括号匹配) ⭐⭐⭐ 队列(BFS标准实现) ⭐⭐⭐ 并查集 ⭐⭐⭐⭐(连通性问(优先队列实现贪心) ⭐⭐⭐ 树状数组 ⭐⭐(区间求和问图论 最小生成树(Prim/Kruskal) ⭐⭐⭐ 单源最短路(Dijkstra) ⭐⭐⭐拓扑排序 ⭐⭐ 数学与数论 初等数论(GCD/质数判断/快速幂) ⭐⭐⭐⭐ 排列组合 ⭐⭐⭐ 模运算与逆元 ⭐⭐ 其他重点 二分查找(边界处理) ⭐⭐⭐⭐ 贪心算法(区间调度/ Huffman树) ⭐⭐⭐ 双指针技巧 ⭐⭐⭐ 这是优快云给出的高频算法 1. 搜索算法(DFS/BFS)** [⭐️⭐️⭐️⭐️⭐️] - **出现场景**:几乎每年必考,如迷宫路径、连通性问、排列组合枚举等。 - **真示例**: - 第七届“剪邮票”问(DFS遍历连通性); - 第十二届“砝码称重”隐含记忆化搜索思想; - 第十四届“接龙数列”(字符串搜索与剪枝)。 --- ### **2. 动态规划(DP)** [⭐️⭐️⭐️⭐️] - **高频子类**: - **背包DP**:如第十二届“砝码称重”(01背包变种); - **线性DP**:第七届“煤球数目”(递推问)、第十四届“接龙数列”(状态转移); - **树形DP**:偶有涉及(如路径计数问)。 --- ### **3. 贪心算法** [⭐️⭐️⭐️⭐️] - **高频型**:区间调度、策略选择。 - **真示例**: - 第四届“翻硬币”(相邻翻转策略); - 第九届“乘积最大”(双指针结合正负分析)。 --- ### **4. 数学与数论** [⭐️⭐️⭐️⭐️] - **高频内容**: - **初等数论**:因数分解、模运算(第十二届“货物摆放”); - **排列组合**:第七届“凑算式”全排列问; - **容斥原理**:整数分解问(第十二届第二场D)。 --- ### **5. 排序与二分查找** [⭐️⭐️⭐️] - **高频应用**: - **快速排序**:第七届填空直接考察代码补全; - **二分答案**:第十二届“直线”问(排序去重优化)。 --- ### **6. 数据结构** [⭐️⭐️⭐️] - **高频结构**: - **栈与队列**:模拟中常见(如第四届“翻硬币”隐含栈思想); - **并查集**:图论连通性问(如最小生成树); - **树状数组/线段树**:区间查询问(近年偶有涉及)。 --- ### **7. 图论** [⭐️⭐️⭐️] - **高频算法**: - **最短路径(Dijkstra/Floyd)**:第十二届“路径”直接考察; - **最小生成树(Kruskal/Prim)**:第十二届第二场“城邦”问; - **拓扑排序**:第十四届“飞机降落”依赖关系问。 二届“货物摆放”); - **排列组合**:第七届“凑算式”全排列问; - **容斥原理**:整数分解问(第十二届第二场D)。 --- ### **5. 排序与二分查找** [⭐️⭐️⭐️] - **高频应用**: - **快速排序**:第七届填空直接考察代码补全; - **二分答案**:第十二届“直线”问(排序去重优化)。 --- ### **6. 数据结构** [⭐️⭐️⭐️] - **高频结构**: - **栈与队列**:模拟中常见(如第四届“翻硬币”隐含栈思想); - **并查集**:图论连通性问(如最小生成树); - **树状数组/线段树**:区间查询问(近年偶有涉及)。 --- ### **7. 图论** [⭐️⭐️⭐️] - **高频算法**: - **最短路径(Dijkstra/Floyd)**:第十二届“路径”直接考察; - **最小生成树(Kruskal/Prim)**:第十二届第二场“城邦”问; - **拓扑排序**:第十四届“飞机降落”依赖关系问。 这是deepseek给我的哪个准确点呢,因为不一样所以请你再回顾一下十六届以前广东省b组的高频算法按出现算法频率,给我输出一下
最新发布
03-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值