好印象深刻的题,前天选拔赛给跪了。怪我这种关键题没敲出来。

题意很简单,给你一串无规则的数列,再给个m值,求出满足 数列和>=m的长度最小的连续子串。。。确实一开始卡住了,因为看数据肯定是nlogn的算法才能过,我和聪哥坐在外面的楼梯上,想了各种方法,我就一直在想前缀和以及 先求出最长连续和 再两边删减等等,刚提出来 就马上否定了。。后来还是聪哥想出个比较靠谱的方案,即二分结果,然后对二分出来的结果 先枚举右端点,再通过二分的结果得到左端点,找到左端点和右端点中间最小的前缀和,用左端点的前缀和 减去 最小的前缀和,如果结果>=m,意味着该二分结果可行,可以继续缩小下去,否则说明不行。

然后我就敲了,结果一直WA,后来知道自己哪里傻逼了,我对二分出来的len,在枚举右端点的时候,直接就是从len到n,0-(len-1)这里就没有枚举右端点,事实是,可能恰好结果就在0-(len-1),真是傻逼

不过这个算法确实是正确的,但还是有时限问题  因为多了个二分,其时间复杂度就变成了 n*logn*logn,所以只好聪哥改了我上面的漏洞之后,果然A了,不过用了1.7s,而且,之后我再提及他的同样的代码,就TLE了,估计是UVA的机器突然又跑慢了。所以这个算法还是有问题的。

后来跟聪哥讨论后觉得二分可能可以去掉不要,确实可以去掉。。。我又傻逼了,这么简单问题没想到,预处理完suffix前缀和之后,题目不就是要求suffix[右端点]-suffix[i]>=m,满足这个条件的 离右端点的最近的点,也就是说  我令 val=suffix[i]<=suffix[右端点]-m,即求离右端点最近的满足>=val的suffix所在的点,如果我线段树里面维护的是suffix的最小值,那么我为了求离右端点最近的,我肯定是对 线段树这样query:假如当前右子树满足 >=val,则优先走右子树,否则如何左子树>=val,则走左子树,如果左右都走不了 就是-1了

这样得到的值必定是离右端点最近的啊啊啊啊。

我真是傻逼

这是之前的思路 算法正确 但是会TLE

#include <iostream>
#include <cstdio>
#define N 500010
#define LL long long
#define lson rt<<1,l,mid
#define rson (rt<<1|1),mid+1,r
using namespace std;
LL suffix[N];
int n,m;
LL tree[N*];
void build(int rt,int l,int r)
{
if (l>=r){
tree[rt]=suffix[l];
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
if (tree[rt<<]>tree[rt<<|])
tree[rt]=tree[rt<<|];
else
tree[rt]=tree[rt<<];
}
LL query(int L,int R,int rt,int l,int r)
{
if (L<=l && r<=R){
return tree[rt];
}
int mid=(l+r)>>;
if (R<=mid){
return query(L,R,lson);
}
if (L>mid){
return query(L,R,rson);
}
return min(query(L,R,lson),query(L,R,rson));
}
int ok(int x)
{
for (int i=;i<=n;i++){ //这里应该从前面开始枚举,比赛的时候就是直接从len开始枚举,导致一直WA。。。虽然改了也不一定会避免时限超时,但总归这样是我敲错了,那样是我们思路错了,性质不一样。
int j=i-x;
if (j<) j=;
LL mini;
if (i==) mini=;
else
mini=query(j,i-,,,n);
if (suffix[i]-mini>=m) return ;
}
return ;
} int main()
{
int t;
scanf("%d",&t);
while (t--){
suffix[]=;
scanf("%d%d",&n,&m);
bool isok=;
for (int i=;i<=n;i++){
scanf("%lld",&num[i]);
suffix[i]=suffix[i-]+num[i];
if (num[i]>=m) isok=;
}
if (isok){
puts("");
continue;
}
if (m<=){
puts("-1");
continue;
}
build(,,n);
int L=,R=n+,mid;
bool flag=;
int ans=-;
while (L<R)
{
mid=(L+R)>>;
if (ok(mid)){
flag=;
ans=mid;
R=mid;
}
else
L=mid+;
}
if (!flag){
puts("-1");
}
else
printf("%d\n",ans);
}
return ;
}
/*
7 7
3 -2 1 6 1 -2 3
*/

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 500010
#define LL long long
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
LL suffix[N];
int n,m;
LL tree[N*];
void build(int rt,int l,int r)
{
if (l>=r){
tree[rt]=suffix[l];
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
if (tree[rt<<]>tree[rt<<|])
tree[rt]=tree[rt<<|];
else
tree[rt]=tree[rt<<];
}
int query(LL val,int L,int R,int rt,int l,int r)
{
if (l>=r)
return l;
int mid=(l+r)>>;
int ret1=-,ret2=-;
if (mid<R) //因为是从顶点开始搜索起的,所以用L和R来控制区间
if(val>=tree[rt<<|]){ //优先找右子树,就能得到最近的点
ret1=query(val,L,R,rson);
}
if (L<=mid)
if (val>=tree[rt<<]){
ret2=query(val,L,R,lson);
}
int ret=max(ret1,ret2);
return ret;
}
int main()
{
int t;
scanf("%d",&t);
while (t--){
suffix[]=;
scanf("%d%d",&n,&m);
bool isok=;
for (int i=;i<=n;i++){
scanf("%lld",&suffix[i]);
if (suffix[i]>=m) isok=;
suffix[i]+=suffix[i-];
}
if (isok){
puts("");
continue;
}
if (m<=){
puts("-1");
continue;
}
build(,,n);
int ans=N;
for (int i=;i<=n;i++){
LL v=suffix[i]-m;
int res=query(v,,i-,,,n); //对每个v 在 0到 i-1的区间里,从线段树的顶点开始搜索起,得到离右端点最近的点。
if (res!=-) ans=min(ans,i-res);
// cout<<i<<" "<<res<<endl;
}
if (ans==N) ans=-;
printf("%d\n",ans);
}
return ;
}

UVA_12697 满足条件的最短连续和 线段树维护的更多相关文章

  1. FJUT3568 中二病也要敲代码(线段树维护区间连续最值)题解

    题意:有一个环,有1~N编号,m次操作,将a位置的值改为b,问你这个环当前最小连续和多少(不能全取也不能不取) 思路:用线段树维护一个区间最值连续和.我们设出两个变量Lmin,Rmin,Mmin表示区 ...

  2. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

  3. 【NOIP模拟】board(线段树维护二进制,树序号化为二进制)

    题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高 ...

  4. cf213E 线段树维护hash

    链接 https://codeforces.com/contest/213/problem/E 题目大意 给出两个排列a.b,长度分别为n.m,你需要计算有多少个x,使 得\(a_1 + x; a_2 ...

  5. [Noi2016]区间[离散化+线段树维护+决策单调性]

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 621  Solved: 329[Submit][Status][D ...

  6. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  7. codeforces Good bye 2016 E 线段树维护dp区间合并

    codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...

  8. CF877E Danil and a Part-time Job 线段树维护dfs序

    \(\color{#0066ff}{题目描述}\) 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 ...

  9. HDU 6155 Subsequence Count 线段树维护矩阵

    Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Oth ...

随机推荐

  1. iOS Burp suite CA证书 HTTPS

    设置好burp suite代理后,在浏览器地址输入http://burp/,下载CA证书: 在iOS上下载CA证书,可通过邮件或百度云等一切iOS可以访问证书文件的方法: 点击证书文件iOS提示安装, ...

  2. vi/vim编辑器基本操作

    一.vi/vim的三种模式 vi编辑器有三种模式:命令模式(command mode).插入模式(Insert mode).底行模式(last line mode). 就是你直接用命令(vi  文件名 ...

  3. UITree_study

    1.Create canvas 2.Add TreeView 3.Subscribe and unsubscribe events(订阅和取消订阅事件) 4.Data bind items it's ...

  4. Go语言 Note

    1.简单的CURD之搭建基础框架 //路由层 func Router(rg *gin.RouterGroup){ rg.GET("/getsupplier", facility.G ...

  5. vue - data 接收 props 的值

    <template>   <div>     <div v-for="todo in a" :key="todo.id"> ...

  6. 通过虚拟机增加Linux的磁盘(分区容量)

    因为安装oracle设置的磁盘空间不足,所以安装失败.这里总结一下如何添加磁盘挂载 1. 右键虚拟机点击设置,然后点击磁盘,点击添加按钮 2.然后点击下一步下一步,直到安装成功 3.然后输入 fdis ...

  7. ROS常用库(二) Serial库(单片机和上位机串口通讯)

    比如我们做了个单片机,在win里面用串口调试助手接收和下发数据,那么在ubuntu里用ros怎么实现?换个说法,怎么实现上位机和下位机的通讯? 首先,用python自带的库就可以实现这个功能. 安装p ...

  8. XV6源代码阅读-文件系统

    Exercise1 源代码阅读 文件系统部分 buf.h fcntl.h stat.h fs.h file.h ide.c bio.c log.c fs.c file.c sysfile.c exec ...

  9. 在web.xml中可以设置jsp标签吗?

    <jsp-config> <taglib> <taglib-uri>http://java.sun.com/jstl/core</taglib-uri> ...

  10. HTML中用自定义字体实现小图标icon(不是原作, 只是一个研究笔记)

    最近在做一个项目时, 研究了一下新浪微博的前端, 看到首页中那个图标了吗, 以前看到这类效果的第一反应就是用一个gif之类的图标做出来!! 但在研究的过程, 发现了一个小技巧, 注意那个em标签中的文 ...