[bzoj P4504] K个串

【题目描述】

兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。

兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第k大的和是多少。

【输入格式】

第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和

接下里一行n个数a_i,表示这个数字序列

【输出格式】

一行一个整数,表示第k大的和

【样例输入】

7 5

3 -2 1 2 2 1 3 -2

【样例输出】

4

【数据范围】

对于20%的数据,1 <= n <= 2000

对于另外20%的数据,0 <= a_i <= 10^9

对于100%的数据,1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9

数据保证存在第k大的和

题外话:好久都没有用博客园啦,最近写博客都写在WordPress上面。没想到今天炸了。。只好先来cnblogs避一避了。

对于这一题我也是一脸懵逼式的弃疗。连想都没怎么想,丝毫没有办法。

结果——主席树+堆。也是看了题解才明白的。自己怎么也想不到这种方法。

主思路是这样的,维护一个五元组(v,l,r,x,p)表示一个状态,分别表示当前状态所对应区间的和(v),左端点所在区间(l,r),左端点的具体位置(x),右端点的具体位置(p)。(这个思路骑士真的太难想到了,主要一个我觉得,习惯于考虑对称的东西,不会像这样,区间左右端点有别)

先不考虑如何如何构造或得到五元组。假设我们可以很快得到某一个特定的五元组。那如何得出第k大的和?

每一次从堆中取出最大值,也就是当前最大的和,然后做这样的事情:

构造五元组(maxsum_val(),l,p-1,maxsum_pos(),p)和(maxsum_val(),p+1,r,maxsum_pos(),p),并将它们push入堆中。显然这是正确的。

那刚开始在堆里的是什么呢?当然是p=1~n时,左端点在某一点能使区间和最大的这个状态咯。

这个问题——涉及到区间修改,区间查询。肯定要用线段树咯。但是我们发现用线段树是无法处理对于不同的右端点p,查询某个区间最值的问题的。

所以我们对于每一种右端点p,建立一颗主席树,然后在对应的主席树上高即可。

code:

 #pragma GCC optimize(2)
 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 #include <map>
 #include <queue>
 #define LL long long
 #define mp make_pair
 #define pli pair <LL,int>

 using namespace std;

 ,M=;

 int n,m; map <int,int> pre;
 struct node {
     LL v; int x,l,r,p;
     node () {}
     node (LL _v,int _x,int _l,int _r,int _p) :
         v(_v),x(_x),l(_l),r(_r),p(_p) {}
     bool operator < (const node &o) const {
         return v<o.v;
     }
 };
 priority_queue <node> q;

 namespace TREE {
     int tot,rt[N],lc[M],rc[M]; pli w[M]; LL tag[M];
     #define mid (((l)+(r))>>1)
     #define ms(a,x) memset(a,x,sizeof a)
     inline ,ms(tag,);}
     inline void build (int &u,int l,int r) {
         w[u=++tot]=mp(,l);
         if (l==r) return;
         build(lc[u],l,mid),build(rc[u],mid+,r);
     }
     inline void insert (int &u,int v,LL z) {
         tag[u=++tot]=tag[v]+z;
         lc[u]=lc[v],rc[u]=rc[v],w[u]=w[v],w[u].first+=z;
     }
     inline void upload (int u) {
         w[u]=max(w[lc[u]],w[rc[u]]);
     }
     inline void download (int &u) {
         insert(lc[u],lc[u],tag[u]),insert(rc[u],rc[u],tag[u]);
         tag[u]=;
     }
     inline void modify (int &u,int v,int l,int r,int x,int y,LL z) {
         if (x<=l&&r<=y) {insert(u,v,z); return;}
         if (tag[u]) download(v);
         lc[u=++tot]=lc[v],rc[u]=rc[v],w[u]=w[v];
         if (x<=mid) modify(lc[u],lc[v],l,mid,x,y,z);
         ,r,x,y,z);
         upload(u);
     }
     inline pli query ()) {
         if (x<=l&&r<=y) return w[u];
         if (tag[u]) download(u);
         if (x<=mid) ret=query(lc[u],l,mid,x,y);
         ,r,x,y));
         return ret;
     }
 } using namespace TREE;

 inline void extend (int x,int l,int r) {
     if (l>r) return;
     pli nxt=query(x,,n,l,r);
     q.push(node(nxt.first,x,l,r,nxt.second));
 }

 int main () {
     scanf(],,n);
     ,x; i<=n; ++i) {
         scanf("%d",&x);
         modify(rt[i],rt[i-],,n,pre[x]+,i,(LL)x);
         extend(rt[i],,i),pre[x]=i;
     }
     node cur;
     for ( ; m; --m) {
         cur=q.top(),q.pop();
         extend(cur.x,cur.l,cur.p-);
         extend(cur.x,cur.p+,cur.r);
     }
     printf("%lld\n",cur.v);
     ;
 }

[bzoj P4504] K个串的更多相关文章

  1. bzoj : 4504: K个串 区间修改主席树

    4504: K个串 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 268  Solved: 110[Submit][Status][Discuss] ...

  2. bzoj 4504: K个串 可持久化线段树+堆

    题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...

  3. BZOJ 4504: K个串

    题目大意: 求一个序列的第k大的子串和. 题解: 对于一个右端点找最优的左端点,扔进堆里. 每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次. 现在需要对于一个固定的右端点, ...

  4. bzoj 4504: K个串【大根堆+主席树】

    像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(d,l,r,p,v)表示右端点为d,左端点区间为(l,r),最大区间和值为v左端点在p上 关于怎么快速求区间和,用可持久化线段树维护(主席树?) ...

  5. bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)

    [fjwc2015]k个串 kstring [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只 ...

  6. 数据结构(主席树):COGS 2213. K个串

    2213. K个串 ★★★★   输入文件:bzoj_4504.in   输出文件:bzoj_4504.out   简单对比时间限制:20 s   内存限制:512 MB [题目描述] 兔子们在玩k个 ...

  7. BZOJ 3110 K大数查询 | 整体二分

    BZOJ 3110 K大数查询 题面 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个 ...

  8. 问题 K: 周期串plus

    问题 K: 周期串plus 时间限制: 1 Sec  内存限制: 128 MB提交: 682  解决: 237[提交] [状态] [命题人:外部导入] 题目描述 如果一个字符串可以由某个长度为k的字符 ...

  9. hiho#1449 重复旋律6 求长度为k的串最大次数 后缀自动机

    题目传送门 题目大意:求长度为k的串的最大次数,把k从1到length的所有答案全部输出. 思路: 这道题放在$SAM$里就是求长度$k$对应的所有$right$集中最大的大小. 我们以$aabab$ ...

随机推荐

  1. mysql 事物没提交导致事物一直运行解决方案

    1.设置 innodb_kill_idle_transaction 参数, 可以永久避免 https://dbaplus.cn/news-11-974-1.html

  2. PAT (Advanced Level) Practice 1001 A+B Format (20 分)

    题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805528788582400 Calculate a+b and ...

  3. vue 去中心化的路由拆分方案:require.context

    代码地址:https://github.com/lisiyizu/vue-router-dynamic

  4. 【题解】Luogu P5284 [十二省联考2019]字符串问题

    原题传送门 我用sa做的本题 (码量似乎有点大) 先对原串建sa 考虑如何建图: 从大到小枚举长度len 先将height中等于len的两个位置在并查集合并起来,将lst也合并(lst是链表) 再将长 ...

  5. FIT2096 Assignment 2 2019

    FIT2096 Assignment 2 2019_v1.2.docx 9/04/2019 11:34 AMPage 1 | 4FIT2096 Assignment 2 2019Transformat ...

  6. 2019-泰迪杯c题数据处理,WGS-84(世界标准地理坐标系) 转为 BD-09(百度地理坐标系)

    2019-泰迪杯c题数据处理,WGS-84(世界标准地理坐标系) 转为 BD-09(百度地理坐标系) 本次泰迪杯的数据为经纬度数据,并且题目给的是WGS-84(世界标准地理坐标系)格式的,所有如果调用 ...

  7. SKCTF Writeup

    签到题 请打开微信关注,发送give me flag,即可获得. Encode 1.ACSCLL 首先看到这类题,我们肯定是要使用ASCLL的(这么明显的提示大家肯定一眼就能看出来),我们可以对照As ...

  8. The application to execute does not exist: 'C:\Users\Administrator\.dotnet\tools\.store\dotnet-aspnet-codegenerator\2.2.0-rtm-35687\dotnet-aspnet-codegenerator\2.2.0-rtm-35687\tools\netcoreapp2.1\any\

    vs code mvc搭建基架执行命令操作出现的问题解决方式重新复制拷贝一份2.2.0命名为2.2.0-rtm-35687, 修改

  9. EF中防止sql注入

    EF作为一个orm框架,本身以及放置了sql的注入,但是如果我们需要执行sql语句的时候了?比如,我们需要查询视图"select * from VM where 条件 = {0}" ...

  10. loj #6.Guess Number

    原题链接:https://loj.ac/problem/6 Guess Number 内存限制:256 MiB 时间限制:1000 ms 题目类型:交互 题目描述 这是一个交互题的模板. 系统会随机生 ...