【UOJ 245】【UER #7】天路

Description

给出一个系列,要求出所有长度为k (1<k<=n) 的序列中,最大值减去最小值的最小值,要求输出答案与正确答案相对误差均不超过 5%

Solution

听CTY说这题一眼看去要用近似算法,我不会(实际上也不用)。
因为答案有一定的浮动,所有考虑一下从答案入手,
枚举k,表示当前做到绝对值差为k,再 O(n) 扫一遍,即可知道适用k的区间最长是多少,更新答案。
我们发现,题目允许答案浮动,所有k不用枚举每一个数,只要枚举1.05的指数即可,即 0,1.050,1.051,1.052,1.053...
发现 1.05300=2273996>106 ,可以过!!!

PS:如 f(i) 单调,并且可以知道 f(i)>k 的第一个i在哪,即可套用这个近似算法。

复杂度: O(nlog2(V))

优化:
1. 用RMQ加log2预处理可以O(1)得出区间最值
2. 可以直接用上一轮的答案*1.05

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstring>
#define foi(i,a,b) for(i=a;i<=b;i++)
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=100050,INF=2147483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n;
int a[N],er[18];
int mi[N*2][18],mx[N*2][18];
int LG[N];
int min(int q,int w){return q<w?q:w;}
int max(int q,int w){return q>w?q:w;}
int MIN(int l,int r){return min(mi[l][LG[r-l+1]],mi[r-er[LG[r-l+1]]+1][LG[r-l+1]]);}
int MAX(int l,int r){return max(mx[l][LG[r-l+1]],mx[r-er[LG[r-l+1]]+1][LG[r-l+1]]);}
int main()
{
    int q=INF,e;double w;
    er[0]=1;fo(i,1,17)er[i]=er[i-1]*2;
    memset(mi,127,sizeof(mi));
    read(n);mi[1][0]=mx[1][0]=read(a[1]);
    fo(i,2,n)q=min(q,abs(a[i-1]-read(a[i]))),mi[i][0]=mx[i][0]=a[i];
    fo(i,1,n)LG[i]=log2(i);
    fo(j,1,LG[n]+1)fo(i,1,n)mi[i][j]=min(mi[i][j-1],mi[i+er[j-1]][j-1]),mx[i][j]=max(mx[i][j-1],mx[i+er[j-1]][j-1]);
    w=q;printf("%d\n",q);e=0;
    for(int I=3;I<=n;)
    {
        w*=1.05;q=0;
        int i=1;
        fo(j,2,n)
        {
            while(MAX(i,j)-MIN(i,j)>w)i++;
            q=max(q,j-i+1);
        }
        fo(j,I,q)printf("%d\n",int(w));
        I=max(I,q+1);
        if(w<1)w=1;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值