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

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;
typedef long long s64; const int ONE = ;
const int MOD = 1e9 + ; int n, k;
s64 val[ONE];
int pre[ONE], suc[ONE];
s64 sum[ONE], sum_B[ONE];
s64 Ans; vector <int> A[ONE], B[ONE]; int get()
{
int res;char c;
while( (c=getchar())< || c> );
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res;
} void Deal_first()
{
int stk[ONE], top = ;
for(int i = ; i <= n; i++)
{
while(top && val[i] > val[stk[top]])
suc[stk[top--]] = i - ;
pre[i] = stk[top] + ;
stk[++top] = i;
}
while(top) suc[stk[top--]] = n; for(int i = ; i <= n; i++)
sum[i] = (sum[i - ] + val[i]) % k;
for(int i = n; i >= ; i--)
sum_B[i] = (sum_B[i + ] + val[i]) % k; for(int i = ; i <= n; i++)
{
A[sum[i]].push_back(i);
B[sum_B[i]].push_back(i);
}
} int Get(int l, int r)
{
int res = sum[r] - sum[l - ];
if(res < ) res += k;
return res;
}
int Find(int R, int val)
{
if(A[val].size() == ) return ;
int l = , r = A[val].size() - ;
while(l < r - )
{
int mid = l + r >> ;
if(A[val][mid] > R) r = mid;
else l = mid;
}
if(A[val][l] > R) return l;
if(A[val][r] > R) return r;
return A[val].size();
}
int Query_left(int L, int R, int val) //sum [L,L~R] num of val
{
if(L > R) return ;
int now = sum[L - ]; //[1, L - 1]
int need = (now + val) % k; //1 ~ R the num of presum = need
return Find(R, need) - Find(L - , need);
}
void Deal_left(int l, int mid, int r)
{
int T = val[mid] % k;
for(int i = l; i <= mid - ; i++)
{
int now = Get(i, mid - );
int need = (T - now + k) % k;
Ans += Query_left(mid, r, need);
} Ans += Query_left(mid, r, T) - ;
} int Get_B(int l, int r)
{
int res = sum_B[l] - sum_B[r + ];
if(res < ) res += k;
return res;
}
int Find_B(int R, int val)
{
if(B[val].size() == ) return ;
int l = , r = B[val].size() - ;
while(l < r - )
{
int mid = l + r >> ;
if(B[val][mid] > R) r = mid;
else l = mid;
}
if(B[val][l] > R) return l;
if(B[val][r] > R) return r;
return B[val].size();
}
int Query_right(int L, int R, int val)
{
if(L > R) return ;
int now = sum_B[R + ];
int need = (now + val) % k;
return Find_B(R, need) - Find_B(L - , need);
}
void Deal_right(int l, int mid, int r)
{
int T = val[mid] % k;
for(int i = mid + ; i <= r; i++)
{
int now = Get_B(mid + , i);
int need = (T - now + k) % k;
Ans += Query_right(l, mid, need);
}
Ans += Query_right(l, mid, T) - ;
} int main()
{
n = get(); k = get();
for(int i = ; i <= n; i++)
val[i] = get(); Deal_first(); for(int i = ; i <= n; i++)
{
if(i - pre[i] + <= suc[i] - i + )
Deal_left(pre[i], i, suc[i]);
else
Deal_right(pre[i], i, suc[i]);
} printf("%lld", Ans);
}

【Codeforces549F】Yura and Developers [单调栈][二分]的更多相关文章

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

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

  2. BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 8748  Solved: 3835[Submi ...

  3. bzoj 4709 [Jsoi2011]柠檬——单调栈二分处理决策单调性

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709 题解:https://blog.csdn.net/neither_nor/articl ...

  4. BZOJ1012最大数 [JSOI2008] 单调栈+二分

    正解:单调栈+二分查找(or,线段树? 解题报告: 拿的洛谷的链接quq 今天尝试学习了下单调栈,然后就看到有个博客安利了这个经典例题?于是就去做了,感觉还是帮助了理解趴quqqqqq 这题,首先,一 ...

  5. 51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

     区间计数   基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80   两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{ ...

  6. 【bzoj4237】稻草人 分治+单调栈+二分

    题目描述 JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要满足以下条件: ...

  7. 洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找)

    洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1333275 这个题不是很 ...

  8. 【洛谷P1823】音乐会的等待 单调栈+二分

    题目大意:给定一个长度为 N 的序列,定义两个数 \(a[i],a[j]\) 相互看得见,意味着 \(\forall k\in [i+1,j-1],a[k]\le a[i],a[k]\le a[j]\ ...

  9. spoj MINSUB 单调栈+二分

    题目链接:点击传送 MINSUB - Largest Submatrix no tags  You are given an matrix M (consisting of nonnegative i ...

随机推荐

  1. oracle数据库之触发器

    触发器是许多关系数据库系统都提供的一项技术.在 ORACLE 系统里,触发器类似过程和函数,都有声明,执行和异常处理过程的 PL/SQL 块. 一. 触发器类型 触发器在数据库里以独立的对象存储,它与 ...

  2. encode 与 decode

    decode 将其它编码的字符串转换成unicode编码,例如:str1.decode("gb2312"),表示将gb2312编码的字符串转换成unicode编码 encode 将 ...

  3. 【IdentityServer4文档】- 整体情况

    整体概况 大多数现代应用程序看起来或多或少像这样: 最常见的交互是: 浏览器与 Web 应用程序进行通信 Web 应用程序与 Web API 进行通信(有时是Web应用程序自己发起,有时代表用户发起) ...

  4. Web后台任务处理

    文章:.NET Core开源组件:后台任务利器之Hangfire Hangfire官网介绍:在.NET和.NET Core应用程序中执行后台处理的简便方法.无需Windows服务或单独的过程. 以持久 ...

  5. iOS- 显示数据列表最常用的一个控件UITableView

    相信做过iOS的程序员,最熟悉的控件一定少不了UITableView,最常用的控件也一定少不了UITableView! 今天分享一下自己对UITableView的实现大体思路,和整理出来的学习笔记! ...

  6. OSG学习:转动的小汽车示例

    由于只是简单的示例,所以小汽车的模型也比较简单,是由简单的几何体组成. 代码如下: #include <osg\ShapeDrawable> #include <osg\Animat ...

  7. vue中使用monaco-editor打包文件混乱的问题

    之前讲述了怎么在vue项目中使用monaco-editor (https://www.cnblogs.com/XHappyness/p/9414177.html),使用是正常的,虽然 npm run ...

  8. Android各分辨率定义的图片规格

    我们定义的app图片规格 app图标需要分iphone和android两套 iphone: 名称 Iphone4 Iphone5 手机尺寸 960*640(高*宽) 1136*640 (高*宽) 电池 ...

  9. Java SE1.6中的Synchronized

    1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本 ...

  10. hdu 3030 Increasing Speed Limits (离散化+树状数组+DP思想)

    Increasing Speed Limits Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...