这道题目不知道是因为做的人少还是什么原因,pass率很低,我在去图书馆的路上忽然想起这道题目和最大连续子序列其实是一个问题,但是更难,更挑剔!
1250. BestSubsequence
Description
LL有n个妹子,他给妹子们编号排成一排。据说今天天气大好,LL要去春游了,他决定要选定至少F个妹子一起去玩。 为了让妹子们开心,他决定选连续一段的妹子们。然后LL有个特殊的癖好,他喜欢体重比较厉害一些的妹子。
那你可以帮LL选妹子吗,使得选出来的这些妹子的平均体重最大。
Input Format
输入第一行两个整数,n和F。
接下来n行,每行一个整数,表示妹子的体重。
对前50%的数据:1<=n<=20。 对100%的数据:1<=n<=100000, 1<=F<=n, 1<=妹子体重<=2000。
Output Format
输出一个整数,为这个平均值乘以1000,不要四舍五入,输出int(avergae * 1000)即可。
Sample Input
10 6 6 4 2 10 3 8 5 9 4 1
Sample Output
6500
题目显得很二逼,忽略这些,我们需要找出连续的子序列其平均值最大,且子序列的长度应该大于F,我们从归纳的角度去想这个问题,如果我们已知前n个人中平均值最大的这个序列,那么对于n+1,这个问题如何求解?
显然如果这个最大序列刚好以n为尾巴,那么n+1如果能够增大这个序列的平均体重,就把n+1加上去形成一个新的最大序列,问题是如果其不以n为结尾呢?此时可能存在一个以n结尾的后缀序列,它虽然不是前n个的最大序列,但是能够和n+1形成一个比当前最大序列更大的新序列,基于这点,我们提出更强的假设:
假设我们已知前n个值的最大序列和最大后缀序列,则只要比较n+1和最大后缀序列是否能够组成比前n个值的最大序列更大的解!
由于我们使用了更强的假设,即P&&Q,所以在求解的时候需要同时更新最大序列和后缀序列的最大值,否则归纳错误。
#include <iostream> using namespace std; int main() { int nums,least_num; int global_max=0,suffix_max=0; int global_num,suffix_num; cin>>nums>>least_num; int *pounds=new int[nums]; for(int i=0;i<nums;i++) { cin>>pounds[i]; } for(int j=0;j<least_num;j++) { global_max+=pounds[j]; } int tp=global_max-pounds[0]; if(least_num==1) { int max=-1; for(int i=0;i<nums;i++) { if(max<pounds[i]) { max=pounds[i]; } } cout<<max*1000<<endl; return 0; } suffix_max=(global_max*1.0/least_num>(global_max-pounds[0])*1.0/(least_num-1))?global_max:(global_max-pounds[0]); global_num=least_num; suffix_num=(global_max>suffix_max)?(least_num-1):least_num; for(int j=least_num;j<nums;j++) { if((pounds[j]+suffix_max)*1.0/(suffix_num+1)>(global_max*1.0/global_num)) { global_max=pounds[j]+suffix_max; global_num=suffix_num+1; } tp=tp+pounds[j]-pounds[j-least_num+1]; if(tp*1.0/(least_num-1)>(suffix_max+pounds[j])*1.0/(suffix_num+1)) { suffix_max=tp; suffix_num=least_num-1; } else { suffix_max+=pounds[j]; suffix_num++; } } int ans=(global_max*1.0/global_num)*1000; cout<<ans<<endl; }
这里需要注意的是如何更新suffix_max,这需要大家去思考,另外有一些小细节也很影响速度,整个过程也是几经修改pass,但思想是不变的,归纳非常强大!