【尺取法】swpu涨姿势之区间刷新
来源:互联网 发布:电视选购 知乎 编辑:程序博客网 时间:2024/06/16 21:01
题目:
value_Dragon是一个有钱人,快过年了,所以他准备发红包,但是他发红包的方式很奇葩,
他让n个人排成一排,每次选择1-n中的一段区间[l,r]发,给区间中的每一个人一块钱,
就这样发了m次红包,发完后他想知道在[l,r]的子区间中有多少个区间满足以下要求:
1.这个区间得到钱的总数不少于s;
2.这个区间可以被分成两个不想交的子区间且每个子区间得到的钱的总数不小于w;
(注:一个区间的子区间包括自己本身)
防坑提醒:长度为1的区间比如[1,1]是不能被分成两个子区间的
输入:
第一行是一个整数T代表数据的组数;
接下来有T组数据
每组数据开头有四个整数,分别代表n m s w;
接下来m行,每行是两个数l,r代表区间[l,r]的左右端点;
其中T<=10;
n<=10^6,m<=10^5;
0<l<=r<=n;
0<=w<=s<10^8;
输出:
对于每组数据输出一行,代表符合要求的区间个数;
样例输入:
4
1 0 0 0
1000000 0 0 0
1000000 1 0 0
1 1000000
10 10 20 14
2 10
5 9
5 5
6 8
2 6
9 10
6 7
6 10
4 5
5 7
样例输出:
0
499999500000
499999500000
小技巧:
尺取法视频链接:点击打开链接
value_Dragon是一个有钱人,快过年了,所以他准备发红包,但是他发红包的方式很奇葩,
他让n个人排成一排,每次选择1-n中的一段区间[l,r]发,给区间中的每一个人一块钱,
就这样发了m次红包,发完后他想知道在[l,r]的子区间中有多少个区间满足以下要求:
1.这个区间得到钱的总数不少于s;
2.这个区间可以被分成两个不想交的子区间且每个子区间得到的钱的总数不小于w;
(注:一个区间的子区间包括自己本身)
防坑提醒:长度为1的区间比如[1,1]是不能被分成两个子区间的
输入:
第一行是一个整数T代表数据的组数;
接下来有T组数据
每组数据开头有四个整数,分别代表n m s w;
接下来m行,每行是两个数l,r代表区间[l,r]的左右端点;
其中T<=10;
n<=10^6,m<=10^5;
0<l<=r<=n;
0<=w<=s<10^8;
输出:
对于每组数据输出一行,代表符合要求的区间个数;
样例输入:
4
1 0 0 0
1000000 0 0 0
1000000 1 0 0
1 1000000
10 10 20 14
2 10
5 9
5 5
6 8
2 6
9 10
6 7
6 10
4 5
5 7
样例输出:
0
499999500000
499999500000
8
思路:运用双指针,左右指针均初始化为1,先移动右指针,再移动左指针,得到一个符合条件的最小区间,最后计算答案是ans+=l,而不是ans+=1;那是因为现在这个l-r的区间是满足条件的最小区间,那么再加上l前的数,一定也满足,所以是ans+=l;
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e6+10;int t,n,m,l,r,w,s,x,y;int a[maxn],sum[maxn];int main(){ scanf("%d",&t); while(t--){ memset(a,0,sizeof(a)); memset(sum,0,sizeof(sum)); scanf("%d%d%d%d",&n,&m,&s,&w); while(m--){ scanf("%d%d",&x,&y); a[x]++;a[y+1]--; //小技巧 } for(int i = 1;i <= n;i++) a[i] = a[i-1] + a[i]; for(int i = 1;i <= n;i++) sum[i] = sum[i-1] + a[i]; ll ans = 0,l = 1,r = 1; for(int i = 1;i <= n;i++){ //得到一个满足条件的最小区间! while(r < i&&sum[i] - sum[r] >= w) ++r; while(l < r-1&&sum[i] - sum[l] >= s&& sum[r-1]-sum[l] >= w) ++l; if(l < r&&sum[i]-sum[l-1] >= s&&sum[i]- sum[r-1] >= w&&sum[r-1]-sum[l-1]>=w) ans += l; } printf("%I64d\n",ans); } return 0;}
小技巧:
m次发红包,每次都要对给定的区间l-r进行刷新+1?当然不用这么繁琐的操作,使用下面的小技巧:
代码:
while(m--){ scanf("%d%d",&x,&y); a[x]++;a[y+1]--; //小技巧 } for(int i = 1;i <= n;i++) a[i] = a[i-1] + a[i];
尺取法视频链接:点击打开链接
阅读全文
0 0
- 【尺取法】swpu涨姿势之区间刷新
- 尺取法 枚举区间
- 区间价值?hihocoder1483《二分!!+尺取法》
- 51NOD1495 中国好区间 【尺取法】
- 2017百度之星初赛(B) 1006 小小粉丝度度熊(区间合并+尺取法)
- 算法学习之尺取法
- hdu6103Kirinriki(第六场尺取法取区间最大)
- 小小粉丝度度熊--尺取法、合并一些重复的区间。
- 【涨姿势】关闭子窗口的同时刷新父窗口
- 常用技巧之 尺取法 【 理解 + 例题 】
- 常用技巧精选之尺取法
- 尺取法
- 尺取法
- 尺取法
- 尺取法
- 尺取法
- 尺取法
- 尺取法
- 母牛繁殖问题
- (OK) MIMP
- Failed to create the Java Virtual Machine
- wordpress安装教程
- .net点选验证码的实例详解
- 【尺取法】swpu涨姿势之区间刷新
- 多人用同一账号操作同一数据 相同权限的人员操作同一数据怎么防止
- VBA
- 对于“大数据”的15条干货思考分享
- Googel 浏览器 模拟发送请求工具--Advanced REST Client
- Linux环境下Eclipse编程小技巧
- VBA中Activate方法和Select方法的区别
- vba常用函数
- OkHttp 使用详情二