题目描述

分析

我们要找的是一段区间的和减去该区间的最大值能否被 \(k\) 整除

那么对于一段区间,我们可以先找出区间中的最大值

然后枚举最大值左边的后缀与最大值右边的前缀之和是否能被 \(k\) 整除

显然暴力枚举肯定会超时

所以我们可以用启发式合并的思想,只枚举长度较小的那一半,而在某种数据结构中查询另一半对应的值

查询的过程可以用主席树,但是常数巨大

其实我们可以对于每一个 \(\%k\) 后的前缀和开一个 \(vector\)

\(vector\) 中存放该值出现的位置

然后大力二分即可,复杂度和主席树相同

注意具体查的值要推一下式子

代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=3e5+5,maxm=1e6+5;
int n,k,a[maxn],sum[maxn],wz[maxn][22],ans,cnt[maxm],lg[maxn],b[maxn];
std::vector<int> g[maxm];
int cx(int l,int r){
rg int k=lg[r-l+1];
if(b[wz[l][k]]<b[wz[r-(1<<k)+1][k]]) return wz[r-(1<<k)+1][k];
else return wz[l][k];
}
int js(int id,int l,int r){
if(l>r || g[id].size()==0 || g[id][g[id].size()-1]<l) return 0;
return std::upper_bound(g[id].begin(),g[id].end(),r)-std::lower_bound(g[id].begin(),g[id].end(),l);
}
void solve(int l,int mids,int r){
if(l>mids || r<mids) return;
solve(l,cx(l,mids-1),mids-1);
solve(mids+1,cx(mids+1,r),r);
if(mids-l<r-mids){
for(rg int i=l;i<=mids;i++){
rg int now=(sum[i-1]+a[mids])%k;
ans+=js(now,mids+1,r);
}
ans+=js(sum[mids-1],l-1,mids-2);
} else {
for(rg int i=mids;i<=r;i++){
rg int now=(sum[i]-a[mids]+k)%k;
ans+=js(now,l-1,mids-2);
}
ans+=js(sum[mids],mids+1,r);
}
}
int main(){
n=read(),k=read();
for(rg int i=1;i<=n;i++){
a[i]=read();
b[i]=a[i];
a[i]%=k;
wz[i][0]=i;
}
for(rg int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
if(sum[i]>=k) sum[i]-=k;
g[sum[i]].push_back(i);
}
for(rg int i=2;i<=n;i++){
lg[i]=lg[i/2]+1;
}
for(rg int j=1;j<=20;j++){
for(rg int i=1;i+(1<<j)-1<=n;i++){
if(b[wz[i][j-1]]>b[wz[i+(1<<(j-1))][j-1]]){
wz[i][j]=wz[i][j-1];
} else {
wz[i][j]=wz[i+(1<<(j-1))][j-1];
}
}
}
g[0].push_back(0);
for(rg int i=0;i<k;i++){
std::sort(g[i].begin(),g[i].end());
}
rg int be=cx(1,n);
solve(1,be,n);
printf("%d\n",ans);
return 0;
}

联赛模拟测试17 A. 简单的区间 启发式合并的更多相关文章

  1. [CSP-S模拟测试]:模板(ac)(线段树启发式合并)

    题目描述 辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了.他每天都被$katarina$大神虐,仗着自己学过一些姿势就给$katarina$大神出了一道题.有一棵$n$个节点的以$1$号节 ...

  2. [CSP-S模拟测试]:english(可持久化Trie+启发式合并)

    题目传送门(内部题24) 输入格式 第一行有$3$个整数$n,opt$,$opt$的意义将在输出格式中提到.第二行有$n$个整数,第$i$个整数表示$a_i$. 输出格式 若$opt=1$,输出一行一 ...

  3. 模拟测试—moq:简单一两句

    在Xunit的基础上,说话模拟测试. 假如我们有这样一个控制器里面有这样一个方法,如图 我们在对Bar测试得时候,如果测试未通过,错误有可能来至于Bar,也有可能错误来至于serverde Foo方法 ...

  4. 联赛模拟测试10 C. 射手座之日

    题目描述 分析 方法一(线段树) 线段树维护的是以当前节点为左端点的区间的贡献 而区间的右端点则会从 \(1\) 到 \(n\) 逐渐右移 当我们把右端点从 \(i-1\) 的位置扩展到 \(i\) ...

  5. [考试反思]0811NOIP模拟测试17:虚无

    (sdfz未参加,也就是一共就51个人) 也不粘具体排名了,只写分数线. []220 []201 []194 [5]181 [10]141 [15]132 [20]122 [25]116 [30]10 ...

  6. NOIP模拟测试17

    T1:入阵曲 题目大意:给定一个N*M的矩形,问一共有多少个子矩形,使得矩形内所有书的和为k的倍数. 60%:N,M<=80 枚举矩形的左上角和右下角,用二维前缀和求出数字之和. 时间复杂度$O ...

  7. 8.11 NOIP模拟测试17 入阵曲+将军令+星空

    T1 入阵曲 前缀和维护可以得60分 f[x1][y1][x2][y2]=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];  O(n4) ...

  8. 联赛模拟测试14 A. 虎

    题目描述 这题太虎了,所以没有背景. 给你一棵树,边有黑白两种颜色,你每次可以选择两个点,把这两个点之间的唯一简单路径上的所有边颜色取反,某些边要求最终颜色必须是黑色,还有些边没有要求,问最少操作多少 ...

  9. 联赛模拟测试20 C. Weed

    题目描述 \(duyege\) 的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹. 为了查出真相,\(duyege\) 准备修好电脑之后再进行一次金坷垃的模拟实验. 电脑上面有若干层金坷垃,每次只能在 ...

随机推荐

  1. 用C#创建Windows服务(Windows Services)

    用C#创建Windows服务(Windows Services) 学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...

  2. mint安装相关数据库lib

    sudo apt-get install libmysqlclient-dev sudo apt-get install sqlite3 libsqlite3-dev

  3. SQLite常用网址

    英文版SQLite官网: http://www.sqlite.org/rescode.html中文版SQLite官网:http://www.helplib.net/s/sqlite/9/167.sht ...

  4. matlab读入矩阵数据

    方法: 很简单,把矩阵数据存到excel里,然后存成cvs的格式,就是把每行数据之间用‘,’分隔:行与行之间用‘\n’保存. 举例: 假设cvs为test_nnfeature.txt,后缀可以改啦,只 ...

  5. 报错处理——# Creating Server TCP listening socket *:6379: bind: Address already in use

    在启动redis时报错 # Creating Server TCP listening socket *:6379: bind: Address already in use 错误原因 6379地址已 ...

  6. 在 Android 手机上运行 Python 程序

  7. Qt绘制文本一

    QPainterPath,使用 drawText且设置字体,再使用painter.drawText方式 效果图: void WgtText::paintEvent(QPaintEvent *event ...

  8. 2018.10.24 bzoj2064: 分裂(状压dp)

    传送门 状压dp好题. 考虑对于两个给出的集合. 如果没有两个元素和相等的子集,那么只能全部拼起来之后再拆开,一共需要n1+n2−2n1+n2-2n1+n2−2. 如果有呢? 那么对于没有的就是子问题 ...

  9. 混沌数学之Arnold模型

    相关软件混沌数学之离散点集图形DEMO 相关代码: class ArnoldEquation : public DiscreteEquation { public: ArnoldEquation() ...

  10. ListView的优化问题

    listview算是我们app中较为常用的控件之一了.而如何优化也是一个问题. listview的优化一般分为两类. 一布局优化. 对布局的优化是大家了解的. 1.复用convertview.andr ...