[POI2015]Wilcze doły

题目大意:

给定一个长度为\(n(n\le2\times10^6)\)的数列\(A(1\le A_i\le10^9)\),可以从中选取不超过\(d\)个连续数字变成\(0\),求一个最长的子串使得这段数的和不超过\(p\)。

思路1:

显然,将\(d\)个修改的机会用完一定最优,答案至少为\(d\)。

二分答案\(k\),\(O(n)\)枚举端点,若区间和-区间最大的长度为\(d\)的子段和\(\le p\),则答案至少为\(k\)。

而“区间最大的长度为\(d\)的子段和”可以用稀疏表维护,时空复杂度均为\(\mathcal O(n\log n)\)。

然而这题空间限制128MB,还要开int64,会MLE,要是空间开到512MB也能过了。

源代码1:

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<algorithm>
  4. typedef long long int64;
  5. inline int64 getint() {
  6. register char ch;
  7. while(!isdigit(ch=getchar()));
  8. register int64 x=ch^'0';
  9. while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
  10. return x;
  11. }
  12. const int N=2e6+1,logN=21;
  13. int n,a[N],d;
  14. int64 p,sum[N],max[N][logN];
  15. inline int lg2(const float &x) {
  16. return ((unsigned&)x>>23&255)-127;
  17. }
  18. inline bool check(const int &k) {
  19. for(register int i=k;i<=n;i++) {
  20. const int l=lg2(k-d+1);
  21. if(sum[i]-sum[i-k]-std::max(max[i-k+d][l],max[i-(1<<l)+1][l])<=p) return true;
  22. }
  23. return false;
  24. }
  25. int main() {
  26. n=getint(),p=getint(),d=getint();
  27. for(register int i=1;i<=n;i++) {
  28. a[i]=getint();
  29. sum[i]=sum[i-1]+a[i];
  30. if(i>=d) max[i][0]=sum[i]-sum[i-d];
  31. }
  32. for(register int j=1;j<=lg2(n-d+1);j++) {
  33. for(register int i=d;i<=n;i++) {
  34. max[i][j]=std::max(max[i][j-1],max[i+(1<<(j-1))][j-1]);
  35. }
  36. }
  37. int l=d+1,r=n;
  38. while(l<=r) {
  39. const int mid=(l+r)>>1;
  40. if(check(mid)) {
  41. l=mid+1;
  42. } else {
  43. r=mid-1;
  44. }
  45. }
  46. printf("%d\n",l-1);
  47. return 0;
  48. }

思路2:

不难发现当右端点单调递增时,能选取的最大的左端点具有单调性。

而“区间最大的长度为\(d\)的子段和”可以用单调队列维护。

时空复杂度\(\mathcal O(n)\)。

源代码2:

  1. #include<queue>
  2. #include<cstdio>
  3. #include<cctype>
  4. typedef long long int64;
  5. inline int64 getint() {
  6. register char ch;
  7. while(!isdigit(ch=getchar()));
  8. register int64 x=ch^'0';
  9. while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
  10. return x;
  11. }
  12. const int N=2e6+1;
  13. std::deque<int> q;
  14. int a[N];
  15. int64 sum[N],tmp[N];
  16. int main() {
  17. const int n=getint();
  18. const int64 p=getint();
  19. const int d=getint();
  20. for(register int i=1;i<=n;i++) {
  21. a[i]=getint();
  22. sum[i]=sum[i-1]+a[i];
  23. if(i>=d) tmp[i]=sum[i]-sum[i-d];
  24. }
  25. int ans=d;
  26. q.push_back(d);
  27. for(register int i=d+1,last=0;i<=n;i++) {
  28. while(!q.empty()&&q.front()-d<last) q.pop_front();
  29. while(!q.empty()&&tmp[q.back()]<=tmp[i]) q.pop_back();
  30. q.push_back(i);
  31. while(!q.empty()&&sum[i]-sum[last]-tmp[q.front()]>p) {
  32. last++;
  33. if(!q.empty()&&q.front()-d<last) q.pop_front();
  34. }
  35. ans=std::max(ans,i-last);
  36. }
  37. printf("%d\n",ans);
  38. return 0;
  39. }

[POI2015]Wilcze doły的更多相关文章

  1. BZOJ 4385: [POI2015]Wilcze doły

    4385: [POI2015]Wilcze doły Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 648  Solved: 263[Submit][ ...

  2. 【BZOJ4385】[POI2015]Wilcze doły 单调栈+双指针法

    [BZOJ4385][POI2015]Wilcze doły Description 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段 ...

  3. BZOJ4385 : [POI2015]Wilcze doły

    求出前缀和$s$,设$f[i]=s[i+d-1]-s[i-1]$. 从左到右枚举的右端点$i$,左端点$j$满足单调性,若$s[i]-s[j-1]-\max(区间内最大的f)\leq p$,则可行. ...

  4. BZOJ4385[POI2015]Wilcze doły——单调队列+双指针

    题目描述 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得该区间内所有数字之和不超过p. 输入 第一行包含三个整数n,p ...

  5. bzoj 4385: [POI2015]Wilcze doły【单调栈】

    对于每个i,以它为左端点的最优右端点一定是单增的,所以用单调栈维护 具体的,单调栈里放的是和单调的长为d的子段,然后枚举右端点,如果这段的和-当前长为d子段最大的和大于p的话,左端点右移同时注意单调栈 ...

  6. 【bzoj4385】[POI2015]Wilcze doły

    单调队列扫描,记录当前区间长度为d的一段的和的最大值,和当前区间和. #include<algorithm> #include<iostream> #include<cs ...

  7. [bzoj4385][POI2015]Wilcze doły_单调队列

    Wilcze doły bzoj-4385 POI-2015 题目大意:给定一个n个数的序列,可以将连续的长度不超过d的区间内所有数变成0,求最长的一段区间,使得区间和不超过p. 注释:$1\le n ...

  8. P3594 [POI2015]WIL-Wilcze doły

    P3594 [POI2015]WIL-Wilcze doły 题目描述 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得 ...

  9. Luogu 3594 [POI2015]WIL-Wilcze doły

    简单题. 考虑没有修改数字的条件的限制,我们直接用双指针扫描就可以计算出答案了. 然后考虑加入修改数字的条件,只要用单调队列维护出当前两个指针表示的区间中长度为$d$的一段区间的最大值,用总和减掉这个 ...

随机推荐

  1. iOS学习笔记(3)— 屏幕旋转

    一.屏幕旋转机制: iOS通过加速计判断当前的设备方向和屏幕旋转.当加速计检测到方向变化的时候,屏幕旋转的流程如下: 1.设备旋转时,系统接收到旋转事件. 2.系统将旋转事件通过AppDelegate ...

  2. Sysmon + NXlog构建简单的windows安全监控

    工具: Sysmon (sysmon 5.0) ,NXlog(nxlog-ce-2.9.1716.msi) . Sysmon监控系统并生成windows event log,   NXlog将wind ...

  3. ASM配置OGG

    两种方法:http://blog.sina.com.cn/s/blog_aa84cfe40101lsks.html 使用ACFS配置OGG:http://ylw6006.blog.51cto.com/ ...

  4. 诺贝斯特(厦门)电气有限公司http://www.thebest.cn.com/

    诺贝斯特(厦门)电气有限公司,公司位于厦门市湖里区塘边社168号.是一家专注于智能电网用户端智能配用电以及电气安全产品研发.生产和销售的高新技术企业:致力于为工矿企业.建筑楼宇以及基础设施等智能电网用 ...

  5. 音频自动增益 与 静音检测 算法 附完整C代码【转】

    转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...

  6. 移动端测试=== adb 无线连接手机

    无线连接(需要借助 USB 线) 除了可以通过 USB 连接设备与电脑来使用 adb,也可以通过无线连接——虽然连接过程中也有需要使用 USB 的步骤,但是连接成功之后你的设备就可以在一定范围内摆脱 ...

  7. 虚拟机 windows xp sp3 原版

    原版的镜像:http://www.7xdown.com/Download.asp?ID=3319&URL=http://d5.7xdown.com/soft2/&file=Window ...

  8. C++类指针类型的成员变量的浅复制与深复制

    本篇文章旨在阐述C++类的构造,拷贝构造,析构机制,以及指针成员变量指针悬空问题的解决.需要读者有较好的C++基础,熟悉引用,const的相关知识. 引言: 类作为C++语言的一种数据类型,是对C语言 ...

  9. day7 反射

    反射是python开发中常用的功能,伴随开发的整个过程,因此要熟练掌握反射的用法. 反射常用的函数有四个:hasattr().getattr().setattr()和delattr()四个反射的函数. ...

  10. 问题:SpringBoot访问不到Controller

    SpringBoot正常启动,其它配置都正常,以下是控制台打印: 解决方法: 将controller与application配置文件同层,是访问时无法扫描到相应的controller,故无法映射到相应 ...