【Codeforces549F】Yura and Developers [单调栈][二分]
Yura and Developers
Time Limit: 20 Sec Memory Limit: 512 MB
Description

Input

Output

Sample Input
5 2 4 4
Sample Output
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 [单调栈][二分]的更多相关文章
- Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并
F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...
- BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 8748 Solved: 3835[Submi ...
- bzoj 4709 [Jsoi2011]柠檬——单调栈二分处理决策单调性
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709 题解:https://blog.csdn.net/neither_nor/articl ...
- BZOJ1012最大数 [JSOI2008] 单调栈+二分
正解:单调栈+二分查找(or,线段树? 解题报告: 拿的洛谷的链接quq 今天尝试学习了下单调栈,然后就看到有个博客安利了这个经典例题?于是就去做了,感觉还是帮助了理解趴quqqqqq 这题,首先,一 ...
- 51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线
区间计数 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{ ...
- 【bzoj4237】稻草人 分治+单调栈+二分
题目描述 JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要满足以下条件: ...
- 洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找)
洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1333275 这个题不是很 ...
- 【洛谷P1823】音乐会的等待 单调栈+二分
题目大意:给定一个长度为 N 的序列,定义两个数 \(a[i],a[j]\) 相互看得见,意味着 \(\forall k\in [i+1,j-1],a[k]\le a[i],a[k]\le a[j]\ ...
- spoj MINSUB 单调栈+二分
题目链接:点击传送 MINSUB - Largest Submatrix no tags You are given an matrix M (consisting of nonnegative i ...
随机推荐
- java知乎爬虫
好久没写博客了,前阵子项目忙着上线,现在有点空闲,就把最近写的一个爬虫和大家分享下,统计结果放在了自己买的阿里云服务器上(点此查看效果),效果如下: 程序是在工作之余写的,用了java 的webmgi ...
- c# word 删除指定内容
1.首先简单的是获取得到的range,直接rangge.delete() 2.文本框的删除: foreach (Microsoft.Office.Interop.Word.Shape shape in ...
- TensorFlow安装解惑
本文整理自网络,若有侵犯请告知. 1.安装环境 目前TensorFlow社区推荐的环境是Ubuntu, 但是TensorFlow同时支持Mac,Windows上的安装部署. 2.关于GPU版本 因为深 ...
- 你代码写得这么丑,一定是因为你长得不好看----panboo第一篇博客
一.个人介绍 我叫潘博,软嵌162,学号1613072055. 以“panboo”名称混迹于各大开源IT论坛与博客. 除了编程,我的最大爱好是篮球与健身,热衷于各种IT技术与运动. 我做过的软件项目有 ...
- 如何重新安装Orchard CMS?
Orchard CMS安装后,配置文件和数据库保存在App_Data目录中.这个目录是受保护的,是不能通过网址访问到的. 如果要完全重装你的站点,你可以删除此目录中的所有文件,但是最好先备份!删除后重 ...
- Qt应用程序图标
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt应用程序图标 本文地址:http://techieliang.com/2017/1 ...
- 网众远程修改ip、dns
修改文件 修改ip vi /etc/rc.d/rc.inetd1.config IPADDR[0] 对应第一块网卡的ip 修改dns vi /etc/resolv.conf nameserver 21 ...
- 使用tc来控制网络流量
https://blog.csdn.net/qinyushuang/article/details/46611709 tc实际操控网络的流量 解释网络tc的架构,从架构上分析tc,与netfilter ...
- 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)
多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢? ...
- Oracle 分页、取期间数据、TOP前几
Oracle没有 sqlserver的 top number 功能.只能以期间的形式实现 代码实现分页,参数curPage 当前页.pageSize 每页行数,计算出起始结束页码 int startP ...