因其兩題具備類似的地方所以合爲一篇題解 ----------題記html
思路:
二分答案
答案即爲平均值ios
如何取check答案是否知足題意,判斷一個知足題意的區間是否>=這個平均值
通常能夠把序列都減去平均值,而後求出前綴和,判斷區間是否大於0(轉化爲斷定性問題)ui
if(sum[i]-min(sum[0]~sum[i-f])>0) return true;//若是成立此時區間平均值較小
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int n,f;const int maxn=1e5+10; int m[maxn];double sum[maxn]; bool check(double mid){ sum[0]=0; for(int i=1;i<=n;++i) sum[i]=sum[i-1]+m[i]-mid; double minv=0; for(int i=0,j=f;j<=n;++i,++j){ minv=min(minv,sum[i]); if(sum[j]>=minv) return true; } return false; } int main(){ scanf("%d%d",&n,&f); for(int i=1;i<=n;++i) scanf("%d",&m[i]); double l=0,r=2000; while(r-l>1e-5){ double mid=(l+r)/2; if(check(mid)) l=mid; else r=mid; }printf("%d",int(r*1000)); }
其實思路有上述大同小異spa
惟一的差異
就是區間 有上限(相似於滑動窗口)code
判斷的時候
應該是這樣htm
if(sum[i]-min(sum[i-t]~sum[i-s]) return 1;
維護必定區間的最小值能夠考慮用到單調隊列blog
bool check(double mid){ for(int i=1;i<=n;++i) sum[i]=sum[i-1]+m[i]-mid; int head=1,tail=0; for(int i=1;i<=n;++i){ if(i>=s){ while(head<=tail && sum[i-s]<sum[q[tail]]) --tail;//擠掉比它大的數 q[++tail]=i-s; } while(q[head]<i-t && head<=tail) ++head; if(sum[i]-sum[q[head]]>=0 && head<=tail) return 1; } return 0; }
ZFY AK IOI隊列