POJ-3061 Subsequence 二分或尺取
题意:给你一个长度为n(n<100000)的数组,让你找到一个最短的连续子序列,使得子序列的和>=m (m<1e9)
题解: 1 显然我们我们可以二分答案,然后利用前缀和判断是否可行,这样是O(nlgn)的 注意没有答案 ans输出0
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<cstring> 5 using namespace std; 6 int T,n,m,a[100005],l,r,ans; 7 int check(int x) 8 { 9 for (int i=1;i<=n-x+1;i++) 10 { 11 if (a[i+x-1]-a[i-1]>=m) return 1; 12 } 13 return 0; 14 } 15 int main() 16 { 17 scanf("%d",&T); 18 while (T--) 19 { 20 memset(a,0,sizeof(a)); 21 scanf("%d%d",&n,&m); 22 for (int i=1;i<=n;i++) 23 { 24 scanf("%d",&a[i]); 25 a[i]+=a[i-1]; 26 } 27 l=1;r=n;ans=0; 28 while (l<=r) 29 { 30 int mid=(l+r)/2; 31 if (check(mid)) 32 { 33 ans=mid; 34 r=mid-1; 35 }else l=mid+1; 36 } 37 printf("%d\n",ans); 38 } 39 }
2 还是一道尺取的裸题,先取前x个数(r++),直到大于m,此时减去该区间最前面的一个数(收缩 l++),再次判断是否大于S,重复操作,直至r==n或取得的区间无法大于S 停止
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<cstring> 5 using namespace std; 6 int sum,T,n,m,a[100005],l,r,ans; 7 int check(int x) 8 { 9 for (int i=1;i<=n-x+1;i++) 10 { 11 if (a[i+x-1]-a[i-1]>=m) return 1; 12 } 13 return 0; 14 } 15 int main() 16 { 17 scanf("%d",&T); 18 while (T--) 19 { 20 memset(a,0,sizeof(a)); 21 scanf("%d%d",&n,&m); 22 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 23 24 ans=n+1;l=1;r=1;sum=0; 25 while (1) 26 { 27 while (r<=n && sum<m) 28 { 29 sum+=a[r]; 30 r++; 31 } 32 if (sum<m) break;else 33 { 34 ans=min(ans,r-l); 35 sum-=a[l]; 36 l++; 37 } 38 } 39 if (ans!=n+1) printf("%d\n",ans);else printf("0\n"); 40 } 41 }
Anderyi!