整体思路:
分解为子问题:在[l,r)区间里查找长度为l的子序列,要求序列和sum≥s,输出sum最小值以及该序列起始位置,代码如下:
int sum=0, flag=0, pos=0, temp=inf; for(int i=1;i<=mid;++i) sum+=a[i]; for(int i=1;i<=n-mid;++i){ if(i>1) sum=sum-a[i-1]+a[i-1+mid];//前缀和实现, 复杂度On if(sum>=s&&sum<temp) {flag=1;temp=sum;pos=i;} } if(flag) cout<<temp<<' '<<pos<<endl; else cout<<-1<<endl;
长度l属于[l, r),利用二分,每次进行子问题操作,记录每一个l对应的sum,pos,整体复杂度nlgn
代码:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; int s, a[2005], k; struct data { int sum; int pos; int len; }d[2005]; void getAnswer(int a[], int n, int s) { int l=1, r=n; while(l<r){ int mid=(l+r)>>1; int sum=0, flag=0, pos=0, temp=inf; for(int i=1;i<=mid;++i) sum+=a[i]; for(int i=1;i<=n-mid;++i){ if(i>1) sum=sum-a[i-1]+a[i-1+mid]; if(sum>=s&&sum<temp) {flag=1;temp=sum;pos=i;} } if(flag) {r=mid;d[k].len=mid, d[k].pos=pos, d[k].sum=temp;k++;} else l=mid+1; } } //3关键字排序,重要程度按序列长度、序列和、起始位置依次递减 bool cmp(data x, data y) { if(x.len==y.len&&x.sum==y.sum) return x.pos<y.pos; if(x.len==y.len) return x.sum<y.sum; return x.len<y.len; } int main() { cin>>s; int n=1; for(int i=1;cin>>a[i]&&a[i]!=-1;++i) ++n; getAnswer(a, n, s); if(k==0) cout<<0<<endl;//没有符合条件的子序列 else { sort(d,d+k,cmp); cout<<d[0].len<<endl; for(int i=d[0].pos;i<d[0].pos+d[0].len;++i) printf("%d%c",a[i]," \n"[i==n-1]); } return 0; } /* 90 1 2 3 4 5 9 10 50 40 23 90 -1 */
此题运用二分思想,特此记录。