隆冬将至,几天后跳蚤国便会迎来寒冬,这对于以血肉之躯和飞机搏斗的跳蚤们来说并不是件好事……然而在悠悠历史岁月中,跳蚤国早已有了应对严寒的应急措施方案! 在跳蚤国王的带领下,跳蚤们准备启动天路热能塔 —— 红米 note7(红米 note7 为发烧而生)。这座热能塔高耸入云,直接穿出大气层从太空中直接吸收太阳光,垂直向下将热能送往跳蚤国各个角落。热能塔的制造工艺巧夺天工,被誉为“带来温暖的天路”。 但是跳晚们为了让跳蚤们都因为天气寒冷赖在被子里不肯起床,在热能塔启动后一定会歇斯底里地进攻。跳蚤国高级间谍的情报显示,跳晚国计划将发射 n台三星 note7 向热能塔发起进攻。进攻将会按一定顺序进行,其中第 ii 次进攻的高度为 ai(1≤i≤n)。 为了防止热能塔被炸毁,跳蚤国王特地派尛焱轟(一种新型交通工具,运载能力是小火车的三次幂)运送来了跳蚤们刚研制出不久的新型材料 —— Nokia1050。跳蚤们将会把 Nokia1050 装在热能塔上的某一连续的高度区间上以抵挡进攻。 现在,跳蚤国王想在热能塔受损程度和材料消耗量之间进行取舍。所以对于每个 2≤k≤n,跳蚤国王想知道整个攻击过程中如果想让 Nokia1050 在某一时段至少挡住连续 k次攻击,那么安装 Nokia1050 的高度区间的长度至少是多少。其中,若高度区间为 [l,r],则长度为 r−l。 事实上,间谍的消息也不见得会多么靠谱,所以跳蚤国王仅想知道一个不那么准确的答案。具体来说:如果对于每个 k你输出的答案 ck与标准答案 c^k 的相对误差均不超过 5%,则算作正确。即:∣ck−c^k∣≤5%⋅c^k输入格式 第一行一个正整数 n,保证 n≥2。 第二行 n个正整数 a1,…,an,按顺序给出每次进攻时三星 note7 的高度。输出格式 输出 n−1行,其中第 k−1行表示至少抵挡连续 k次攻击时所需的最短高度区间长度。(2≤k≤n) 因为十分重要所以说两遍,如果对于每个 kk 你输出的答案 ck与标准答案 c^k的相对误差均不超过 5%,则算作正确。即:∣ck−c^k∣≤5%⋅c^k样例一 input 4 1 7 5 2 output 2 5 6 explanation 当 k=2时,最优高度区间为 [5,7]; 当 k=3时,最优高度区间为 [2,7]; 当 k=4 时,最优高度区间为 [1,7]; 注意 k=2时不能选择高度区间 [1,2],虽然能够拦截下第 1次和第 4次攻击,但这两次攻击并不连续。样例二 input 10 26 723 970 13 422 968 875 329 234 983 output 93 546 639 734 749 957 957 957 970 explanation 样例输出给出的为准确答案,注意下面的输出也是可接受的: 93 540 630 730 740 960 960 960 970
【题解】【近似算法+RMQ】
【算法一】【线段树或RMQ维护区间最大最小值,暴力求解。期望得分:50分】
【正解来袭!】
【这是一个求解近似值的题,从前貌似没做过。。。】
【其实,我们可以从求准确值开始考虑:那么,即上面50分的做法,枚举长度暴力求解。但我们会发现:近似的是答案而不是区间长度,这样做根本没法近似。所以,我们考虑枚举结果,每次查找当前结果所能满足的最长距离即可。这样我们就可以近似了:枚举时答案的跨越长度是1.05(至于为什么是1.05,我表示我也不清楚。。。hxy说应该是根据允许5%的误差范围选的,好像很有道理!)。】
【查找每次的距离时,我们可以用两个指针t1、t2,如果当前区间[t1,t2]的答案还小于当前的答案,那么,我们将t2后移,否则将t1后移。在判断区间[t1,t2]的答案时,我们用RMQ来查询。】
【RMQ预处理每个区间的最大值和最小值,可以做到O(1)查询】
#include[附UOJ题解]#include #include #include using namespace std;int maxn[100010][20],minn[100010][20],mi[100010];int ans[100010],n,a[100010];inline void pre(){ for(int j=1;j<20;++j) for(int i=1;i<=n;++i) if(i+(1<<(j-1))<=n) { maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]); minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); } for(int i=1;i<=n;++i) { int k=0; while((1< <=i) ++k; mi[i]=k-1; }}inline int get_cha(int l,int r){ int ans1=0,ans2=0,k=mi[r-l+1]; ans1=max(maxn[l][k],maxn[r-(1< 1;--i) ans[i]=min(ans[i],ans[i+1]); for(i=2;i<=n;++i) printf("%d\n",ans[i]); return 0; }
[反正我没大看懂。。。]