买糖吃
题目描述:
洋神带着他的小伙伴去买糖吃。
洋神想要一款特殊的糖果。柜台上的这种糖果是用一个圆圈穿起来的n颗糖果。每颗糖果有自己的美味值。商家会根据顾客的需求,从中选出连续x颗糖果卖给顾客。这串糖果的美味值是这x颗糖果美味值的平均值。
洋神的胃口不大,他希望他的糖果由[L,R]颗糖组成。而且他想要使得这串糖果的美味值最大。为了方便和小伙伴分享糖果,洋神希望这串糖果的个数是偶数。
看小数是一件麻烦的事情,请你用整数或者分数的形式,告诉洋神最大的美味值。
输入格式:
第一行,包含三个整数,n,L,R。
第二行,n个整数,代表每一颗糖果的美味值。
输出格式:
一个数,表示美味值ai。
样例输入:
5 3 4 3 1 2 4 5
样例输出:
7/2
提示:
1≤L≤R≤n≤10^5
0≤ai≤10^9
数据随机生成。
时间限制:1000ms
空间限制:256MByte
这就是那道坑害了我很久的题目,刚开始的时候连题目的意思都没有看懂,主要是他希望他的糖果由[L,R]颗糖果组成那个部分。其实就是说糖果的数量num,L<=num<=R,语文是真的不行。然后接下来贴一下刚开始自己写的爆零代码。
#include<bits/stdc++.h> using namespace std; double s; int a[200001],le,ri,n,up,down,sum=0; int main(){ cin>>n>>le>>ri; for (int i=1; i<=n; i++){ cin>>a[i]; a[i+n]=a[i]; } if (le%2==1) le++; for (int i=le; i<=ri; i+=2){ s=-1;//对,就是这里。 for (int l=1; l<=n; l++){ sum=0; for (int k=1; k<=i; k++){ sum+=a[l+k-1]; } if (sum*1.0/i>s) { up=sum; down=i; s=sum*1.0/i*1.0; } } } int o=__gcd(up,down); if (down/o!=1) cout<<up/o<<"/"<<down/o; else cout<<up/o; return 0; }
对就是那个地方,我只要把s=-1给放到那层for的外面就可以拿到五十分,我也不知道我那个时候怎么想的居然会把s=-1放到里面去。然后把代码改了一下(就是把s=-1放到外面,还有for的小小优化),发现比五十分只多了二十分
#include<bits/stdc++.h> using namespace std; double s; int a[200001],le,ri,n,up,down,sum=0; int main(){ cin>>n>>le>>ri; for (int i=1; i<=n; i++){ cin>>a[i]; a[i+n]=a[i]; } if (le%2==1) le++; s=-1; for (int i=le; i<=ri && i<=2*le/*for的小小优化*/; i+=2){ for (int l=1; l<=n; l++){ sum=0; for (int k=1; k<=i; k++){ sum+=a[l+k-1]; } if (sum*1.0/i>s) { up=sum; down=i; s=sum*1.0/i*1.0; } } } int o=__gcd(up,down); if (down/o!=1) cout<<up/o<<"/"<<down/o; else cout<<up/o; return 0; }
最后就要来说一下看起来逼格很高的前缀和,听学长讲这一题的时候就是一脸懵逼??前缀和?这是什么东西,后来经过我和同桌数学大佬的一番探讨发现其实就是求和!对没错就是放一个sum数组(程序里用的是num),用sum[i]来存前i个数的总和。这就是传说中的前缀和。用前缀和可以让程序跑得比之前快的原因,就是在刚开始的时候将每一个和值求出来,这样在后来的操作中只要将sum[k]-sum[l-1]就能得到在k到l这段区间内所有数字的和。这样就不用在程序中每次求连续n个数的和都要一次次地跑了,好,新技能get,接下来就是AC代码,其实和爆零代码的字数差距并不是很大
#include<bits/stdc++.h> using namespace std; double s; int a[200001],le,ri,n,up,down,sum=0,num[200001]={0}; int main(){ cin>>n>>le>>ri; for (int i=1; i<=n; i++){ cin>>a[i]; a[i+n]=a[i]; } if (le%2==1) le++; s=-1; num[1]=a[1]; num[0]=0; for (int i=2; i<=n*2; i++) num[i]=num[i-1]+a[i]; for (int i=le; i<=ri && i<=2*le; i+=2){ for (int l=le; l<=2*n; l++){ sum=num[l]-num[l-i]; if (sum*1.0/i>s) { up=sum; down=i; s=sum*1.0/i*1.0; } } } int o=__gcd(up,down); if (down/o!=1) cout<<up/o<<"/"<<down/o; else cout<<up/o; return 0; }
qwq,后来试了一下,只要有前缀和就算不用for里面的小小优化也是可以的。前缀和自己应该能够想到的啊,那个毒性极强的s=-1;放在for里面坑害的太深了,诶,不应该啊。。(qwq,html好难,多亏有同桌大佬)
made by cain-