4385: [POI2015]Wilcze doły

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 648  Solved: 263
[Submit][Status][Discuss]

Description

给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0。
请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。

Input

第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16)。
第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9)。

Output

包含一行一个正整数,即修改后能找到的最长的符合条件的区间的长度。

Sample Input

9 7 2
3 4 1 9 4 1 7 1 3

Sample Output

5

HINT

将第4个和第5个数修改为0,然后可以选出区间[2,6],总和为4+1+0+0+1=6。

Source

[Submit][Status][Discuss]

分析

显然单调队列O(N)扫过去即可,就是注意优化常数。

代码

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; #define gc getchar
#define add(x,y) x=x*10+y-'0' template <class T>
__inline void read(T &x)
{
x = ; char c = gc(); while (c < '')
c = gc(); while (c >= '')add(x,c),
c = gc();
} #define mem(x) memset(x,0,sizeof(x))
#define rep(x) for(int i=1;i<=x;++i) #define ll long long
#define LL long long #define N 4000005 int n;
int d;
int num[N];
int que[N]; LL p;
LL sum[N];
LL mex[N]; signed main(void)
{
read(n);
read(p);
read(d); rep(n)read(num[i]);
rep(n)sum[i] = sum[i - ] + num[i];
rep(n - d + )mex[i] = sum[i + d - ] - sum[i - ]; int h = , t = , lt = , ans = ; for (int i = d; i <= n; ++i)
{
while (h < t && mex[que[t - ]] <= mex[i - d + ])
--t; que[t++] = i - d + ; while (sum[i] - sum[lt] - mex[que[h]] > p)
{
++lt; while (que[h] <= lt)++h;
} if (i - lt > ans)ans = i - lt;
} printf("%d\n", ans);
}

BZOJ_4385.cpp

 #include <bits/stdc++.h>

 typedef long long longint;

 const int maxn = ;

 int n;
int d;
int num[maxn];
int que[maxn]; longint p;
longint sum[maxn];
longint mex[maxn]; signed main(void)
{
scanf("%d%lld%d", &n, &p, &d); for (int i = ; i <= n; ++i)
scanf("%d", num + i); for (int i = ; i <= n; ++i)
sum[i] = sum[i - ] + num[i]; for (int i = ; i <= n - d + ; ++i)
mex[i] = sum[i + d - ] - sum[i - ]; int head = , tail = , left = , answer = ; for (int i = d; i <= n; ++i) {
while (head < tail && mex[que[tail - ]] <= mex[i - d + ])
--tail; // queue pop back que[tail++] = i - d + ; while (sum[i] - sum[left] - mex[que[head]] > p) {
++left;
while (que[head] <= left)
++head; // queue pop front
} if (answer < i - left)
answer = i - left;
} printf("%d\n", answer);
}

BZOJ_4385.cpp

@Author: YouSiki

05-06 14:03