Yura and Developers

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

Input

Output

  

Sample Input

  4 3
  5 2 4 4

Sample Output

  2

HINT

Solution

  首先,我们先用单调栈求出以点 i 作为最大值的区间 [pre_i,  suc_i]。然后显然就是 求 [pre_i, suc_i]有几个区间的和val[i] %k同余

  我们记区间为 [L, mid, R](i 为mid,pre_i 为 L,suc_i 为R),显然我们可以枚举长度小的半个区间。这时效率是O(nlogn)的。

  那么只要能求出另外一半的贡献即可,假定我们枚举 [L, mid - 1] 的一个 点begin。那么 [begin, mid - 1] 的和是固定的,我们又知道总和应该为多少(%k同余)。所以我们就可以知道剩下需要提供多少值。 问题就转化为了求:[mid, mid ~ R] 中有几个以 mid 为左端点,mid~R为右端点的区间 的和 %k余 一个定值。

  我们考虑这个东西怎么求,显然可以将问题转化为查前缀和形式

    我们已知 [1, mid - 1] 的和%k的值,又由于[mid, mid~R] 要提供一个定值的贡献,所以可以算出 [1, mid~R] 要余多少

  那么我们就可以通过查前缀和解决这个子问题,现在的问题又转化为了 如何查询一个区间 [L, R] 内某一定值数的个数

    显然我们可以 把位置加入在一个以值为下标的vector中,在这个vector中,二分查询位置<=R的个数即可,减去 <=(L - 1) 的即可。

  这样我们就解决了假定[L, mid - 1]固定的一部分,假定[mid + 1, R]固定同理。

  我们就解决了这道题啦!QWQ

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<vector>
  9 using namespace std;
 10 typedef long long s64;
 11
 12 const int ONE = 1000005;
 13 const int MOD = 1e9 + 7;
 14
 15 int n, k;
 16 s64 val[ONE];
 17 int pre[ONE], suc[ONE];
 18 s64 sum[ONE], sum_B[ONE];
 19 s64 Ans;
 20
 21 vector <int> A[ONE], B[ONE];
 22
 23 int get()
 24 {
 25         int res;char c;
 26         while( (c=getchar())<48 || c>57 );
 27         res=c-48;
 28         while( (c=getchar())>=48 && c<=57 )
 29         res=res*10+c-48;
 30         return res;
 31 }
 32
 33 void Deal_first()
 34 {
 35         int stk[ONE], top = 0;
 36         for(int i = 1; i <= n; i++)
 37         {
 38             while(top && val[i] > val[stk[top]])
 39                 suc[stk[top--]] = i - 1;
 40             pre[i] = stk[top] + 1;
 41             stk[++top] = i;
 42         }
 43         while(top) suc[stk[top--]] = n;
 44
 45         for(int i = 1; i <= n; i++)
 46             sum[i] = (sum[i - 1] + val[i]) % k;
 47         for(int i = n; i >= 1; i--)
 48             sum_B[i] = (sum_B[i + 1] + val[i]) % k;
 49
 50         for(int i = 1; i <= n; i++)
 51         {
 52             A[sum[i]].push_back(i);
 53             B[sum_B[i]].push_back(i);
 54         }
 55 }
 56
 57 int Get(int l, int r)
 58 {
 59         int res = sum[r] - sum[l - 1];
 60         if(res < 0) res += k;
 61         return res;
 62 }
 63 int Find(int R, int val)
 64 {
 65         if(A[val].size() == 0) return 0;
 66         int l = 0, r = A[val].size() - 1;
 67         while(l < r - 1)
 68         {
 69             int mid = l + r >> 1;
 70             if(A[val][mid] > R) r = mid;
 71             else l = mid;
 72         }
 73         if(A[val][l] > R) return l;
 74         if(A[val][r] > R) return r;
 75         return A[val].size();
 76 }
 77 int Query_left(int L, int R, int val) //sum [L,L~R] num of val
 78 {
 79         if(L > R) return 0;
 80         int now = sum[L - 1]; //[1, L - 1]
 81         int need = (now + val) % k; //1 ~ R the num of presum = need
 82         return Find(R, need) - Find(L - 1, need);
 83 }
 84 void Deal_left(int l, int mid, int r)
 85 {
 86         int T = val[mid] % k;
 87         for(int i = l; i <= mid - 1; i++)
 88         {
 89             int now = Get(i, mid - 1);
 90             int need = (T - now + k) % k;
 91             Ans += Query_left(mid, r, need);
 92         }
 93
 94         Ans += Query_left(mid, r, T) - 1;
 95 }
 96
 97
 98 int Get_B(int l, int r)
 99 {
100         int res = sum_B[l] - sum_B[r + 1];
101         if(res < 0) res += k;
102         return res;
103 }
104 int Find_B(int R, int val)
105 {
106         if(B[val].size() == 0) return 0;
107         int l = 0, r = B[val].size() - 1;
108         while(l < r - 1)
109         {
110             int mid = l + r >> 1;
111             if(B[val][mid] > R) r = mid;
112             else l = mid;
113         }
114         if(B[val][l] > R) return l;
115         if(B[val][r] > R) return r;
116         return B[val].size();
117 }
118 int Query_right(int L, int R, int val)
119 {
120         if(L > R) return 0;
121         int now = sum_B[R + 1];
122         int need = (now + val) % k;
123         return Find_B(R, need) - Find_B(L - 1, need);
124 }
125 void Deal_right(int l, int mid, int r)
126 {
127         int T = val[mid] % k;
128         for(int i = mid + 1; i <= r; i++)
129         {
130             int now = Get_B(mid + 1, i);
131             int need = (T - now + k) % k;
132             Ans += Query_right(l, mid, need);
133         }
134         Ans += Query_right(l, mid, T) - 1;
135 }
136
137 int main()
138 {
139         n = get();    k = get();
140         for(int i = 1; i <= n; i++)
141             val[i] = get();
142
143         Deal_first();
144
145         for(int i = 1; i <= n; i++)
146         {
147             if(i - pre[i] + 1 <= suc[i] - i + 1)
148                 Deal_left(pre[i], i, suc[i]);
149             else
150                 Deal_right(pre[i], i, suc[i]);
151         }
152
153         printf("%lld", Ans);
154 }

View Code

转载于:https://www.cnblogs.com/BearChild/p/7687652.html

【Codeforces549F】Yura and Developers [单调栈][二分]相关推荐

  1. 【Codeforces 549F】Yura and Developers | 单调栈、启发式合并、二分

    题目链接:https://codeforces.com/problemset/problem/549/F 题目大意: 给定一个序列和一个mod值,定义[l,r]合法当l到r的所有元素和减去其中的最大值 ...

  2. Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并

    F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...

  3. Loj#2880-「JOISC 2014 Day3」稻草人【CDQ分治,单调栈,二分】

    正题 题目链接:https://loj.ac/problem/2880 题目大意 给出平面上的nnn个点,然后求有多少个矩形满足 左下角和右上角各有一个点 矩形之间没有其他点 1≤n≤2×105,1≤ ...

  4. bzoj 4237: 稻草人(CDQ分治+单调栈+二分)

    4237: 稻草人 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1352  Solved: 594 [Submit][Status][Discus ...

  5. BZOJ 2388--旅行规划(分块单调栈二分)

    2388: 旅行规划 Time Limit: 50 Sec  Memory Limit: 128 MB Submit: 405  Solved: 118 [Submit][Status][Discus ...

  6. 单调栈 or 线段树扫描线 ---- E. Delete a Segment [单调栈+二分] [扫描线处理空白位置的技巧乘2]

    题目链接 题目大意: 给出nnn个线段代表集合,现在问若可以将其中任意一个线段删除,则能够形成最多多少个独立的集合(取并集后) 解题思路1: 首先我们先对线段按照起点排序 那么我们枚举删除的线段iii ...

  7. Looksery Cup 2015 F. Yura and Developers(单调栈+二分+分治)(难*)

    题目链接 题意:给定一个数组,问有多少区间满足:去掉最大值之后,和是k的倍数. 思路:日后补. #include<bits/stdc++.h> using namespace std; t ...

  8. BZOJ1767/Gym207383I CEOI2009 Harbingers 斜率优化、可持久化单调栈、二分

    传送门--BZOJCH 传送门--VJ 注:本题在BZOJ上是权限题,在Gym里面也不能直接看,所以只能在VJ上交了-- 不难考虑到这是一个\(dp\). 设\(dep_x\)表示\(x\)在树上的带 ...

  9. 后缀数组 ---- 2018~2019icpc焦作H题[后缀数组+st表+二分+单调栈]

    题目链接 题目大意: 给出nnn个数,定义f[l,r]f[l,r]f[l,r]表示 区间[l,r][l,r][l,r]的最大值,求所有 子区间的最大值的和,要求相同的子区间只能算一次 比如数列 5 6 ...

最新文章

  1. windows下如何正确使用Jconsole远程连接linux主机上的JVM
  2. 管道过滤器模式(Pipe and Filter)与组合模式(修改)
  3. Django2.2-LookupError No installed app with label admin
  4. 今天项目中遇到的一个问题:判断新闻Id是否存在
  5. 无法加载安装程序库 wbemupgd.dll
  6. 周思进:产品和服务在“骂”与“被骂”中不断打磨
  7. TypeScript+vue使用与迁移经验总结
  8. mysql5.7循环,python3.4用循环往mysql5.7中写数据并输出的实现方法
  9. 修改Tomcat欢迎界面为自己项目界面
  10. 分页加载PullToRefreshLayout+PullableListView
  11. 专利号校验码php,电子专利证书的三种下载操作方法
  12. 2019-CS224n-Assignment2
  13. 视频时代的下一幕 ABC Inspire:读懂视频
  14. 【圆梦名企第三季】4月12日软件业“人才留湘 引才入湘”专项行动
  15. 自动化测试到底该怎么学?
  16. 超级好用的视频转换器Cisdem Video Converter for Mac
  17. 云服务器怎么安装虚拟显卡,云服务器怎么弄图形界面
  18. 计算机开关电源的发展,开关电源发展史及发展趋势剖析
  19. 一个月过软考|软件设计师中级考试经验分享
  20. spring boot 一个极简单的 demo 示例

热门文章

  1. 假期七天实习参观有感
  2. 《掌握需求过程》阅读笔记三
  3. java并发编程基础-ReentrantLock及LinkedBlockingQueue源码分析
  4. Apache Thrift - 可伸缩的跨语言服务开发框架
  5. 装了linux开机出现错误,[已解决]安装完,启动出现错误!
  6. js Maximum call stack size exceeded
  7. AngularJS入门(用ng-repeat指令实现循环输出)
  8. 开源jeecms,jeebbs学习笔记4——从jo_user表看持久层设计
  9. Android Service 详解一:概述
  10. 自己动手写ORM框架