POJ 3061 Subsequence
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7307 | Accepted: 2710 |
Description
Input
Output
Sample Input
2 10 15 5 1 3 5 10 7 4 9 2 8 5 11 1 2 3 4 5
Sample Output
2 3
首先用一个数组sum[i]维护一个前缀和,sum[0]=0,sum[i]=sum[1]+sum[2]+……+sum[i];
然后可知区间(s,t]的和就是sum[t]-sum[s];
之后可以枚举所有满足sum[t]>s的t,对每个t用二分查找的方法在前面找到满足条件且与它距离最近的s,求出最小值即可
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 int n,s; 7 int sum[100010]; 8 9 int main() 10 { 11 int kase; 12 13 scanf("%d",&kase); 14 15 while(kase--) 16 { 17 int temp,t=-1; 18 sum[0]=0; 19 scanf("%d %d",&n,&s); 20 for(int i=1;i<=n;i++) 21 { 22 scanf("%d",&temp); 23 sum[i]=sum[i-1]+temp; 24 if(t==-1&&sum[i]>=s) 25 t=i; 26 } 27 if(t==-1) 28 { 29 printf("0\n"); 30 continue; 31 } 32 int ans=n; 33 for(;t<=n;t++) 34 { 35 int l=0,r=t-1; 36 while(r-l>1) 37 { 38 int mid=(r+l)/2; 39 if(sum[t]-sum[mid]>=s) 40 l=mid; 41 else 42 r=mid-1; 43 } 44 if(sum[t]-sum[r]>=s) 45 l=r; 46 if(t-l<ans) 47 ans=t-l; 48 } 49 printf("%d\n",ans); 50 } 51 52 return 0; 53 }
在《挑战程序设计竞赛》书上看到了用尺取法优化到O(n)的做法,例如Sample Input中第一组数据:
5 1 3 5 10 7 4 9 2 8
s t ans=5
5 1 3 5 10 7 4 9 2 8
s t ans=4
5 1 3 5 10 7 4 9 2 8
s t ans=3
5 1 3 5 10 7 4 9 2 8
s t ans=2
5 1 3 5 10 7 4 9 2 8
s t ans=2
5 1 3 5 10 7 4 9 2 8
s t ans=2
5 1 3 5 10 7 4 9 2 8
s t ans=2
5 1 3 5 10 7 4 9 2 8
s t ans=2
可知最终答案是2
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 int n,s; 7 int sum[100010]; 8 9 int main() 10 { 11 int kase; 12 13 scanf("%d",&kase); 14 15 while(kase--) 16 { 17 int temp,l=0,r=-1; 18 sum[0]=0; 19 scanf("%d %d",&n,&s); 20 for(int i=1;i<=n;i++) 21 { 22 scanf("%d",&temp); 23 sum[i]=sum[i-1]+temp; 24 if(r==-1&&sum[i]>=s) 25 r=i; 26 } 27 if(r==-1) 28 { 29 printf("0\n"); 30 continue; 31 } 32 int ans=n; 33 while(true) 34 { 35 if(sum[r]-sum[l]>=s) 36 { 37 if(r-l<ans) 38 ans=r-l; 39 l++; 40 } 41 else 42 { 43 if(r==n) 44 break; 45 r++; 46 } 47 } 48 printf("%d\n",ans); 49 } 50 51 return 0; 52 }