【ACM算法竞赛日常训练】DAY5题解与分析【储物点的距离】【糖糖别胡说,我真的不是签到题目】| 前缀和 | 思维

DAY5共2题:

  • 储物点的距离(前缀和)

  • 糖糖别胡说,我真的不是签到题目(multiset,思维)

? 作者:Eriktse
? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?
? 原文链接(阅读原文获得更好阅读体验):https://www.eriktse.com/algorithm/1096.html

储物点的距离

题目链接:https://ac.nowcoder.com/acm/problem/14683

预处理出各点搬运到点1和点n的代价前缀和,以及区间重量和。

假如我们要将区间[5, 7]的物品全部搬运到3,代价应该是区间[5, 7]的物品全部搬运到的1,然后减去多搬的代价:[5, 7]的重量和 * dist(1, 3)。

上面是x < l的情况,x > r的情况类似。

l <= x <= r只需将区间[l, r]分为两部分求和即可。

记得取模,距离要取模,前缀和也要取模。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 2e5 + 9, p = 1e9 + 7;
//sum_l[i]表示区间[1, i]的物品都运到点1的代价之和
//prefix_a[i]表示区间[1, i]的物品重量之和
//pos[i]是第i个点的位置,通过a[]作前缀和得到
int a[maxn], pos[maxn], sum_l[maxn], sum_r[maxn], prefix_a[maxn];
int n, m;

//取模函数
int mo(int x){return (x % p + p) % p;}

int f(int x, int l, int r)
{
    if(l > r)return 0;
    int res = 0;
    if(x <= l)
    {
        res = mo(sum_l[r] - sum_l[l - 1]);
        res = mo(res - mo(pos[x] - pos[1]) * mo(prefix_a[r] - prefix_a[l - 1]) % p);
    }
    else if(x >= r)
    {
        res = mo(sum_r[r] - sum_r[l - 1]);
        res = mo(res - mo(pos[n] - pos[x]) * mo(prefix_a[r] - prefix_a[l - 1]) % p);
    }
    return res;
}

signed main()
{
    scanf("%lld %lld",&n, &m);
    pos[1] = 1;
    for(int i = 2, d;i <= n; ++ i)scanf("%lld", &d), pos[i] = pos[i - 1] + d;
    for(int i = 1;i <= n; ++ i)scanf("%lld", a + i);
    
    for(int i = 1;i <= n; ++ i)
    {
        sum_l[i] = mo(sum_l[i - 1] + a[i] * mo(pos[i] - pos[1]) % p);
        sum_r[i] = mo(sum_r[i - 1] + a[i] * mo(pos[n] - pos[i]) % p);
    }

    
    for(int i = 1;i <= n; ++ i)prefix_a[i] = mo(prefix_a[i - 1] + a[i]);
    
    while(m --)
    {
        int x, l, r;scanf("%lld %lld %lld", &x, &l, &r);
        int ans = 0;
        
        if(l <= x and x <= r)ans = mo(f(x, l, x - 1) + f(x, x + 1, r));
        else ans = f(x, l, r);
        
        printf("%lld\n", ans);
    }
    
    return 0;
}

糖糖别胡说,我真的不是签到题目

题目链接:https://ac.nowcoder.com/acm/problem/14583

本题有两种解法,第一种容易理解,第二种效率更优。

第一种解法:正向,multiset。

发功次数可以用一个桶来记录,让[1, i]的所有点的属性值都+1,相当于把后面的都-1,用一个fix表示偏移量。

建立两个multiset表示两组中的糖糖,好处是可以快速找出能力值最小的,从而去除掉。

扫一遍,把第i只糖糖加入到属于它的集合中,然后将另外一个集合中已有的能力值小的糖糖进行删除,再检查此时是否有发功。

最后集合中留下的糖糖个数即为答案。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 9, inf = 8e18;

struct Node
{
	int a, b;
}p[maxn];

int add[maxn];

void solve()
{
	int n, m;scanf("%lld %lld",&n, &m);
    memset(add, 0, sizeof(int) * (n + 2));
	for(int i = 1;i <= n; ++ i)
		scanf("%lld %lld", &p[i].a, &p[i].b);
    
	//注意同一时间可能施法多次
	for(int i = 1, x;i <= m; ++ i)scanf("%lld", &x), add[x] ++;
    
	int fix = 0, cnt = 0;
    multiset<int> st[2];
    
	for(int i = 1;i <= n; ++ i)
    {
        int a = p[i].a, b = p[i].b - fix;
        
        st[a].insert(b);
        
        while(!st[a ^ 1].empty() and *st[a ^ 1].begin() < b)
            st[a ^ 1].erase(st[a ^ 1].begin()), cnt ++;
        
        fix += add[i];
	}
	printf("%lld\n", n - cnt);
}

signed main()
{
	int _;scanf("%lld", &_);
	while(_ --)solve();
	return 0;
}

第二种解法:反向,思维。

我们想这么一个问题,一个糖糖x是否会被删除取决于x出现之后,在另外一个集合中,是否出现了能力值高于x的能力值的糖糖y

那么我们逆向遍历,维护两个集合的最值,当前的新加入的糖糖x的能力值如果低于另外一个集合中已经存在的(即右边的)糖糖能力值的最大值,说明他后面会被某个糖糖y删除掉,直接打上标记,但是我们不用真的删除。

糖糖x还可以用于删除左边的另一个集合的能力值较小的糖糖。注意此时的发功应该在循环开始时进行修改。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 9, inf = 8e18;

struct Node
{
	int a, b;
}p[maxn];

int add[maxn];

void solve()
{
	int n, m;scanf("%lld %lld",&n, &m);
    memset(add, 0, sizeof(int) * (n + 2));
	for(int i = 1;i <= n; ++ i)
		scanf("%lld %lld", &p[i].a, &p[i].b);
    
	//注意同一时间可能施法多次
	for(int i = 1, x;i <= m; ++ i)scanf("%lld", &x), add[x] ++;
    
	int fix = 0, cnt = 0;
    int mx[2] = {-inf, -inf};
    
	for(int i = n;i >= 1; -- i)
    {
        fix += add[i];
        int a = p[i].a, b = p[i].b + fix;
        mx[a] = max(mx[a], b);
        
        if(mx[a ^ 1] > b)cnt ++;
        
	}
	printf("%lld\n", n - cnt);
}

signed main()
{
	int _;scanf("%lld", &_);
	while(_ --)solve();
	return 0;
}

? 本文由eriktse原创,创作不易,如果对您有帮助,欢迎小伙伴们点赞?、收藏⭐、留言?

原文链接:https://www.cnblogs.com/eriktse/p/17265935.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:【ACM算法竞赛日常训练】DAY5题解与分析【储物点的距离】【糖糖别胡说,我真的不是签到题目】| 前缀和 | 思维 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • Java数据结构之双向链表的实现

    Java数据结构之双向链表的实现 一、双向链表的定义 双向链表是一种包含两个指针的链表数据结构,每个节点都有两个指针,一个指向前一个节点,一个指向后一个节点。 二、双向链表的实现 1. 定义节点 首先,我们需要定义一个节点类,包含节点的值,指向前一个节点的指针pre和指向后一个节点的指针next,代码如下: public class Node { int v…

    数据结构 2023年5月17日
    00
  • Java数据结构之有向图设计与实现详解

    Java数据结构之有向图设计与实现详解 什么是有向图 有向图是一种图形结构,其中每一个节点都有一个方向,即它指向或被其他节点指向。有向图可以用来表示许多实际问题,如路线、依赖关系、状态转移等。 有向图的基本概念 在有向图中,每一个节点都有一个唯一的标识符,被称为节点ID。如果从节点A到节点B存在一条有向边,则称B是A的后继节点,A是B的前驱节点。节点的度数是…

    数据结构 2023年5月17日
    00
  • Java 数据结构与算法系列精讲之贪心算法

    Java 数据结构与算法系列精讲之贪心算法 什么是贪心算法? 在计算机科学中,贪心算法是一种通过选择局部最优解来实现全局最优解的优化算法。贪心算法在解决某些最优化问题时非常有效,贪心算法能够达到接近最优解,有时甚至能够达到最优解。 贪心算法解题步骤: 建立算法模型 找出最优解的子结构 设计贪心选择策略 实现贪心选择策略为一个最优解 证明贪心算法的正确性 贪心…

    数据结构 2023年5月17日
    00
  • C语言编程简单却重要的数据结构顺序表全面讲解

    C语言编程简单却重要的数据结构顺序表全面讲解 什么是顺序表? 顺序表是一种线性表,指的是一组有限元素的有限序列,其元素的逻辑顺序与它们在分配到的内存地址上的物理顺序相同或者等价。也就是说,顺序表中的元素按照其在内存中的位置依次存放。 顺序表的实现方式 顺序表的实现方式一般是使用数组,数组中的每一个元素对应着顺序表中的一个元素,位置相对应。 顺序表的优点 支持…

    数据结构 2023年5月17日
    00
  • python实现汉诺塔递归算法经典案例

    Python实现汉诺塔递归算法经典案例 汉诺塔问题是计算机科学中的经典问题,它是一个递归问题,可以用递归算法来解决。本文将详细讲解Python实现汉诺塔递归算法的完整攻略,包括算法原理、Python实现过程和示例说明。 算法原理 汉诺塔问题是一个经典的递归问题,它的基本思想是将一个大问题分解成若干个小问题,然后逐个解决这些小问题,最终得到大问题的解。具体来说…

    python 2023年5月13日
    00
  • python3实现单目标粒子群算法

    下面是详细讲解“Python3实现单目标粒子群算法”的完整攻略,包括算法原理、Python实现和两个示例。 算法原理 粒子群算法是一种基于群体智能的优化算法,其主要思想是通过模拟鸟群或鱼群等群体的行为,寻找最优解。在单目标粒子群算法中,每个个体用一个向量表示,通过不断更新速度和位置,寻找最优解。 单目标粒子群算法的实现过程如下: 初始化粒子群,包括每个粒子的…

    python 2023年5月14日
    00
  • 【华为OD机试 2023】专栏介绍 +华为OD机试介绍+ 真题目录【转载】

    华为题库说明 2022与2023题库的区别 华为OD机试的题库是季度更新的(Q1\Q2\Q3\Q4)。笔者专栏的题库分为2023和2022。 2023的题库是包括2022.11(Q4第四季度)之后以及2023年的题库。 2022的题库是包括2022.11(Q4第四季度)之前题库。 支持的语言 目前大部分题 使用C++ Java JavaScript 以及py…

    算法与数据结构 2023年4月17日
    00
  • 数据结构 – 绪论

    01.绪论 1. 概念 1.1 数据结构 数据 Data:信息的载体。能被计算机识别并处理的符号的集合。 数据元素 Data element:数据的基本单位,通常作为一个整体进行考虑和处理。一个数据元素往往由若干数据项组成。数据项是组成数据元素的不可分割的最小单位。 如学生的信息记录就是一个数据元素,它由学号、姓名、性别等组成。 数据对象 Data obje…

    算法与数据结构 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部