UVALive2678 http://122.207.68.93:9090/csuacmtrain/problem/viewProblem.action?id=453§ |
【題目描述】:n個正整數組成的序列。給定整數S,求長度最短的連續序列,使他們的和大于等于S。 |
【算法分析】: 【二分】: 全是正整數,保證取的連續序列長度越長,和越可能大于等于S,所以滿足二分的單調遞增的條件,而這里,我們要找的最優解是最小的長度,就是和剛剛好大于等于S的區間長度。 【區間和優化到O(N)】: 使用C[i]數組,做差求和。方法不細說。要求自己,以后遇到區間求和問題,自然就要想到這個。 【運籌分析】: 決策方案:所有區間段,sigm(n+(n-1).......+1)?==?O(n^2)注意n<=10^5 限制條件:累和大于等于S 最優評判標準:區間長度最小 |
【完整代碼】: 1 #include<iostream> 2 3 #include<stdio.h> 4 5 #include<string.h> 6 7 #include<algorithm> 8 9 #include<stdlib.h> 10 11 #include<math.h> 12 13 #include<queue> 14 15 #include<vector> 16 17 #include<map> 18 19 #define MAXN 100000+5 20 21 #define MAXM 20000+5 22 23 #define oo 9556531 24 25 #define eps 0.000001 26 27 #define PI acos(-1.0)//這個精確度高一些 28 29 #define REP1(i,an) for(int i=0;i<=(n);i++) 30 31 #define REP2(i,n) for(int i=1;i<=(n);i++) 32 33 using namespace std; 34 35 //這道題不是dp,而是二分,一是因為dp本身會超時,二是連續的狀態是單調遞增的 36 37 int A[MAXN]; 38 39 int C[MAXN]; 40 41 int n,s; 42 43 bool isok(int l) 44 45 { 46 47 for(int i=l;i<=n;i++) 48 49 if(C[i]-C[i-l]>=s) return true;//優化到O(n) 50 51 return false; 52 53 } 54 55 int main() 56 57 { 58 59 while(cin>>n>>s) 60 61 { 62 63 C[0]=0; 64 65 for(int i=1;i<=n;i++) 66 67 { 68 69 cin>>A[i]; 70 71 C[i]=C[i-1]+A[i]; 72 73 } 74 75 int l=1,r=n+1; 76 77 while(l<r)//邊界條件,保證能夠跳出循環,找不到極值也可,畫狀態圖確定 78 79 { 80 81 int m=(l+r)/2; 82 83 if (isok(m)) r=m;else l=m+1;//根據除2取左的特點,保證能取到極值點 84 85 } 86 87 if (isok(l)) cout<<l<<endl;else cout<<0<<endl; 88 89 } 90 91 return 0; 92 93 } ? ? |
【關鍵詞】:二分,思維 |
轉載于:https://www.cnblogs.com/little-w/p/3525273.html