我的妈呀...真的好长时间没有去做题了,开始做啦
今天的这道题只是一个二分
但是思维很好(毕竟刘神都不会)
这道题是在看算法进阶二分的时候看到的题目,用刘神的话讲,套路啦
思维1:二分出一个答案,并且将所有的值减去该答案,然后得到一个新的序列bi如果满足条件的连续区间,其累加和一定大于或等于零
思维2:如何O(n)求出该答案是否成立,就是计算出新的序列bi的前缀和si,如果在1到i-m之间存在j使得s[i]-s[j]>=0,则答案一定成立
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> //#include<bits/stdc++.h> using namespace std; int n,m; long long a[100010],b[100010],l=200000000,r=0,mid,c[100010]; bool work(long long p) { c[0]=0; b[0]=0; long long Min=1ll*200000000000; for(int i=1;i<=n;i++) { b[i]=b[i-1]+a[i]-p; c[i]=min(c[i-1],b[i]); } c[0]=0; for(int i=n;i>=m;i--) { if(b[i]-c[i-m]>=0)return true; } return false; /*for(int i=1;i<=n;i++){ b[i]=b[i-1]+a[i]-p; if(i>=m) Min=min(b[i-m],Min);//更新Min if(b[i]-Min>=0) return 1; } return 0;*/ } int main() { //freopen("xf.in","r",stdin); //freopen("xf.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); a[i]*=1000; l=min(l,a[i]); r=max(r,a[i]); } while(l+1<r) { mid=(l+r)>>1; if(work(mid))l=mid; else r=mid; } if(work(r))printf("%lld ",r); else printf("%lld ",l); return 0; }
不过在开始的时候,我在不同的oj上(poj,luogu,duoxiao)都会出现一个点的WA,最后感谢刘神帮我检查出了bug,原来是我的c[0]其实
是存在意义的,不能赋值为无穷大,改为0就a掉了