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. ubuntu 16.04 安装jdk9错误

    转自:https://askubuntu.com/questions/769467/can-not-install-openjdk-9-jdk-because-it-tries-to-overwrit ...

  2. Java 8中 基本数据类型

    1)四种整数类型(byte.short.int.long):    byte:8 位,用于表示最小数据单位,如文件中数据,-128~127    short:16 位,很少用,-32768 ~ 327 ...

  3. VBA 实现学校上课教员一学期中所有上课时间,在一页中通过背景底色反应出来

    需求:学校一学期的所有课程表,每个教员都有可能上好几门课,但给一个教员调课时需要查找所调课时间位置有没有此教员上其它的课 相冲突,手动查找很不方便,这里想通过一个表中位置显示出同一教员在所有课表中出现 ...

  4. 【Json】Newtonsoft.Json高级用法

    手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...

  5. codeforces 730 j.bottles

    J. Bottles time limit per test 2 seconds memory limit per test 512 megabytes input standard input ou ...

  6. [CF1060F]Shrinking Tree

    description codeforces 给一棵\(n\)个节点的树,每次等概率选择树中剩下边的一条进行缩边,这条边的两个端点有相同的概率被保留,求最后每个点被留下的概率. data range ...

  7. [CF1083B]The Fair Nut and Strings

    题目大意:在给定的长度为$n(n\leqslant5\times10^5)$的字符串$A$和字符串$B$中找到最多$k$个字符串,使得这$k$个字符串不同的前缀字符串的数量最多(只包含字符$a$和$b ...

  8. 洛谷 P4175 [CTSC2008]网络管理 解题报告

    P4175 [CTSC2008]网络管理 题目描述 带修改树上链的第\(k\)大 输入输出格式 输入格式: 第一行为两个整数\(N\)和\(Q\),分别表示路由器总数和询问的总数. 第二行有\(N\) ...

  9. AOJ.850 电缆公司的烦恼 (二分+枚举)

    AOJ.850 电缆公司的烦恼 (二分+枚举) 题意分析 从[1,average]二分枚举长度即可,由于保留2位小数,可以将数据扩大10^2倍后后枚举,输出时除100即可. 代码总览 #include ...

  10. [zhuan]VMware中bridge方式网络不能上网的解决办法

    http://jingpin.jikexueyuan.com/article/31601.html 安装好VMware 7后,打开原来的虚拟机文件,发现不能上网,原来的Ethernet是设置的Brid ...