题目链接:https://ac.nowcoder.com/acm/contest/882/C

来自:山东大学FST_stay_night的的题解,加入一些注释帮助理解神仙代码。

好像题解被套了一次又一次

要学习的地方我觉得是2点:

1.使用dp(贪心)的思想求出每段所在的连续段

2.因为前缀和是连续变化的,可以用lazy标记来代替树状数组来维护。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; #define ERR(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); } void err(istream_iterator<string> it) {
cerr << "\n";
}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << "=" << a << ", ";
err(++it, args...);
} #define ERR1(arg,n) { cerr<<""<<#arg<<"=\n "; for(int i=1;i<=n;i++) cerr<<arg[i]<<" "; cerr<<"\n"; }
#define ERR2(arg,n,m) { cerr<<""<<#arg<<"=\n"; for(int i=1;i<=n;i++) { cerr<<" "; for(int j=1;j<=m;j++)cerr<<arg[i][j]<<" "; cerr<<"\n"; } } const int INF = 0x3f3f3f3f;
const int MAXN = 10000000, MAXM = 1000000; int l[MAXM + 5], r[MAXM + 5], f[MAXM + 5], g[MAXM + 5];
int sum[MAXN * 3 + 5], b[MAXN * 3 + 5], c[MAXN * 3 + 5]; int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d%d", &l[i], &r[i]);
f[1] = r[1] - l[1] + 1;
//f[i]以i段右端点为结尾的能构造出的最大的前缀和
for(int i = 2; i <= n; i++)
f[i] = max(0, f[i - 1] - (l[i] - r[i - 1] - 1)) + r[i] - l[i] + 1;
//0:以i-1段右端点结尾的能构造出的最大的前缀和都不足够跨过[i-1,i]之间的-1
//f[i - 1] - (l[i] - r[i - 1] - 1):跨过之后还剩下多少贡献给这段
g[n] = r[n] - l[n] + 1;
//g[i]以i段左端点为开头的能构造出的最大的前缀和
for(int i = n - 1; i >= 1; i--)
g[i] = max(0, g[i + 1] - (l[i + 1] - r[i] - 1)) + r[i] - l[i] + 1;
//ERR1(f, n);
//ERR1(g, n);
int i = 1, base = 10000000;
ll ans = 0;
while(i <= n) {
int j = i + 1;
while(j <= n && g[j] + f[j - 1] >= l[j] - r[j - 1] - 1) {
//说明这个[j-1,j]之间的-1段可以因为两侧的f[j-1]和g[j]足够大而连接起来
j++;
}
j--;
//此时j是从i开始最远能够连接到的区间
int left = max(0, l[i] - g[i]), right = min(1000000000 - 1, r[j] + f[j]);
//left,right是至少会产生一个贡献的范围
//ERR(left, right);
int t = i, mi = INF, mx = 0;
sum[0] = 0;
for(int k = left; k <= right; k++) {
//统计这一整段可连接区间的前缀和
if(k >= l[t] && k <= r[t])
sum[k - left + 1] = sum[k - left] + 1;
else
sum[k - left + 1] = sum[k - left] - 1;
if(k == r[t])
t++;
mi = min(mi, sum[k - left + 1] + base);
mx = max(mx, sum[k - left + 1] + base);
//b记录前缀和出现过的次数
b[sum[k - left + 1] + base] ++;
}
//ERR1(sum, right);
//b记录前缀和出现过的次数的后缀和
for(int k = mx - 1; k >= mi; k--)
b[k] += b[k + 1];
//包含最左侧点的贡献
ans += b[base + 1];
for(int k = left; k <= right; k++) {
t = sum[k - left + 1] + base;
//t表示k位置sum的值
//b[t+1]比t大的值的个数
//c[t+1]比在k位置左侧的比t大的值的个数的lazy
b[t + 1] -= c[t + 1]; //把lazy加上去
c[t] += c[t + 1] + 1; //lazy标记下移
c[t + 1] = 0; //清空lazy
ans += b[t + 1];
}
for(int k = mi; k <= mx; k++)
b[k] = 0, c[k] = 0;
i = j + 1;
}
printf("%lld", ans);
return 0;
}

2019牛客暑期多校训练营(第二场) - J - Go on Strike! - 前缀和预处理的更多相关文章

  1. 2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵. 思路: 单调栈 全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如: 1 0 0 1 ...

  2. 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论

    LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...

  3. 2020牛客暑期多校训练营 第二场 K Keyboard Free 积分 期望 数学

    LINK:Keyboard Free 我要是会正经的做法 就有鬼了. 我的数学水平没那么高. 三个同心圆 三个动点 求围成三角形面积的期望. 不会告辞. 其实可以\(n^2\)枚举角度然后算出面积 近 ...

  4. 2020牛客暑期多校训练营 第二场 I Interval 最大流 最小割 平面图对偶图转最短路

    LINK:Interval 赛时连题目都没看. 观察n的范围不大不小 而且建图明显 考虑跑最大流最小割. 图有点稠密dinic不太行. 一个常见的trick就是对偶图转最短路. 建图有点复杂 不过建完 ...

  5. 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心

    LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...

  6. 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心

    LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...

  7. 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP

    LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...

  8. 2019牛客暑期多校训练营(第九场) D Knapsack Cryptosystem

    题目 题意: 给你n(最大36)个数,让你从这n个数里面找出来一些数,使这些数的和等于s(题目输入),用到的数输出1,没有用到的数输出0 例如:3  4 2 3 4 输出:0 0 1 题解: 认真想一 ...

  9. 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题)

    layout: post title: 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题) author: "luowentaoaa" c ...

  10. 2019牛客暑期多校训练营(第二场)F.Partition problem

    链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...

随机推荐

  1. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

  2. Pyenv虚拟环境的创建(虚拟机)

    创建pyenv虚拟环境 sudo yum install openssl* 安装其所需要的库文件 git clone https://github.com/yyuu/pyenv.git ~/.pyen ...

  3. Java几种常见的排序算法

    一.所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面. ...

  4. 湫湫系列故事——设计风景线 HDU - 4514

    题目链接:https://vjudge.net/problem/HDU-4514 题意:判断没有没有环,如果没有环,通俗的讲就是找出一条最长的路,相当于一笔画能画多长. 思路:dfs判环. 最后就是没 ...

  5. 通过Powershell修改文件默认打开方式

    修改原理 详情: Windows下通过注册表修改某个类型文件的默认打开方式和文件图标 脚本详情: Github:Change_default_programs.ps1 描述: 至少在Windows10 ...

  6. java文字转语音播报功能的实现方法

    java文字转语音播报功能的实现方法 一.pom.xml引入jar包依赖 <!-- https://mvnrepository.com/artifact/com.jacob/jacob 文字转语 ...

  7. PHP 的一些底层知识

    本篇内容比较干涩,请自备矿泉水 文章分6个主题进行讲解 PHP运行机制和原理 PHP底层变量数据结构 PHP传值赋值中的COW特性 PHP垃圾回收机制 PHP中数组底层分析 PHP数组函数分类 PHP ...

  8. unity 四叉树管理场景

    当场景元素过多时,需要实时的显示及隐藏物体使得性能提示,但是物体那么多,怎么知道哪些物体需要显示,哪些物体不需要显示的.当然,遍历物体判断该物体是否可以显示是最容易想到的方法,但是每次更新要遍历所有物 ...

  9. template.demo.js

    <!DOCTYPE html><html><head> <title>index</title> <meta charset=&quo ...

  10. 转载 | CSS实现单行、多行文本溢出显示省略号(…)

    本文引自:https://www.cnblogs.com/wyaocn/p/5830364.html 首先,要知道css的三条属性. overflow:hidden; //超出的文本隐藏 text-o ...