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. wwnjld团队第二轮迭代成员分数

    2014-01-05 第二轮迭代团队内成员分数如下(依据分数分配规则以及团队会议协商所得结果): 吴渊渊 23 汪仁贵 21.5 高小洲 19.5 聂建 22.5 吕家辉 23.5 程志 10

  2. java定时执行任务(一)

    需求: 经常遇到这样的需求:要求每天执行一次任务,执行任务时间是凌晨3点 实现: 为了便于检测,我假设的是下一分钟执行任务,每10秒重复执行.(对应现实项目:每天3点执行任务.那么就是下一个3点执行任 ...

  3. kmeans算法理解及代码实现

    github:kmeans代码实现1.kmeans代码实现2(包含二分k-means) 本文算法均使用python3实现 1 聚类算法   对于"监督学习"(supervised ...

  4. lintcode-148-颜色分类

    148-颜色分类 给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红.白.蓝的顺序进行排序. 我们可以使用整数 0,1 和 2 分别代表红,白,蓝. 注意事项 ...

  5. Personal summary 个人总结

    一.请回望开学时的第一次作业,你对于软件工程课程的想象 对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强计算机专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方面达 ...

  6. document,element,dom对象api详解

    Document对象: 根元素的访问,也就是HTML标签的访问.使用document.documentElement访问根对象. 使用Document对象查找对象 getElementById():通 ...

  7. 火狐浏览器(FireFox)安装Flash插件失败处理方法

    最近不知道怎么了,总是嫌弃IE,可能是被网络流量监测的网址给搞得了,弄了火狐浏览器,也安装了猎豹,这里不对浏览器做评价 好多朋友安装好火狐(FireFox)的时候发现之前不是有装IE的Flash播放插 ...

  8. spring cloud 之 客户端负载均衡 Ribbon

    一.负载均衡 负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性.其意 ...

  9. 使用WebClient类对网页下载源码,对文件下载保存及异步下载并报告下载进度

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAx4AAAI7CAIAAADtTtpYAAAgAElEQVR4nO3dX6xlV33Y8f3UJFUqHq

  10. request 域 个人理解

    1.转发到另一个servlet时候 地址还是输入当前的servlet 2.通过服务器转到另一个servlet时候 另一个servlet是最终接收端 端到端模式 相当于这个东西是发给自己的 只不过经过多 ...