二分算法:平均值(洛谷 UVA1451)
生活随笔
收集整理的這篇文章主要介紹了
二分算法:平均值(洛谷 UVA1451)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
解析
這道題尋找平均值的max,答案明顯具有單調性,所以采用二分算法
從0到1不斷取中點mid作為平均值的可能點,看是否存在不短于l的數列均值>=mid不難得到以下代碼:
現在的問題就是要解決這個check函數的寫法了
因為N范圍到1e5,暴力的On方肯定是會超的
我們想到可以先把數組都減mid,這樣就轉化為是否存在不短于L的數列加和大于等于0的問題
我們用s[i]表示1到i的加和
那么a到b的和可以轉化為s[b] - s[a-1](其中b-a+1 >=l)
要使s[b] - s[a-1]最大,就要使s[a-1]取的是s[0]到s[b-l+1]的最大值
而隨著b從l循環到n,每次s[a-1]只加入了一個可能取的元素,故只需與該新值取min,不必遍歷
代碼如下:
這樣check函數的時間復雜度就為O(n)
AC快樂~~~~~~
代碼
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int M = 2e9; int n,l,t; int zuo,you; int f[100500]; bool check(double x){double s[100500]={ };s[1]=f[1] - x;for(int i=2;i<=n;i++){s[i] = s[i-1] + f[i] -x;//求減完x的前綴和 }double mn=M;for(int i=l;i<=n;i++){mn=min(mn,s[i-l]);if(s[i]-mn>=0) return true;//只要存在就返回true }return false; } int main(){scanf("%d",&t);for(int k=1;k<=t;k++){scanf("%d%d",&n,&l);for(int i=1;i<=n;i++){scanf("%1d",&f[i]);}double st=0,ed=1;for(int i=1;i<=10;i++){double mid=(st+ed)/2;if(check(mid)) st=mid;else ed=mid;}double x=st;double s[100500]={ };s[1]=f[1] - x;for(int i=2;i<=n;i++){s[i] = s[i-1] + f[i] -x;}int a,flag=0;double mn=M;for(int i=l;i<=n;i++){if(mn>s[i-l]){mn=s[i-l];a=i-l;}if(s[i]-mn>=0){if(flag==0){zuo=a+1;you=i;flag=1;}else if(you-zuo>i-a){zuo=a+1;you=i;}}}printf("%d %d\n",zuo,you);}return 0; }祝大家rp++!
總結
以上是生活随笔為你收集整理的二分算法:平均值(洛谷 UVA1451)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “此WINDOWS副本不是正版”彻底解决
- 下一篇: 字符串:凯撒密码(洛谷P1914)