随机 Random

题目


  • 暴力

    写起来简单,考场没时间写正解也能骗30分
    时间复杂度: O(N3)

#include<iostream>
#include<cstdio>
using namespace std;
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
const int MAXN=1e6,INF=1e9+1;
int na[MAXN+1];
int n;
int abs(int x){return x<0?-x:x;}
int main()
{
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    int i,j,k,un;
    int minv=INF,ans=INF;
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",&na[i]);
    for(i=1;i<n;i++)
    {
        for(j=i+1;j<=n;j++)
        {
            minv=INF;
            for(k=i;k<=j-1;k++)
                if(minv>abs(na[j]-na[k]))
                    minv=abs(na[j]-na[k]);
            un=j-i+1;
            if(ans>max(minv,un)) ans=max(minv,un);
        }
    }
    printf("%d\n",ans);
    return 0;
}

  • 尺取法

    把第三重循环去掉,重点在break;那句,若最小差值已经小于区间长度,则没有必要继续第二层循环,因为此时权值取决于区间长度,而继续第二层循环的话区间长度只会越来越大
    时间复杂度: O(N2)
    然而……仍然不是正解,不过90分到手也不错了╭(╯^╰)╮

for(int i=1;i<n;i++){
    minv=INF;
    for(int j=i+1;j<=n;j++){
        tmp=abs(a[i]-a[j]);
        if(minv>tmp){
            minv=tmp;
            un=j-i+1;
            if(un<tmp)
                ans=min(ans,minv);
            else{
                ans=min(ans,un);
                break;
            }
        }
    }
}

  • 正解
#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
inline void readi(int &x);
const int maxn=1000005;
int n,ans,a[maxn];

multiset<int> val,dta;                  //两个平衡树; 

void Ins(int x)                         // 插入操作; 
{
    multiset<int>::iterator it,pre,nex;//定义迭代器变量; 
    pre=nex=it=val.insert(x);   // 在平衡树val中插入当前值,迭代器变量赋当前插入值得位置为初值; 
    if(it!=val.begin())     //如果不在平衡树顶部则平衡树dat中插入新生成的和前一个值的差值; 
    {
        pre--;
        dta.insert(*it-*pre);
    }
    nex++;
    if(nex!=val.end())  //如果不在平衡树底部则在平衡树dat中插入新生成的和后一个值的差值;
    {
        dta.insert(*nex-*it);
        if(it!=val.begin())
            dta.erase(dta.find(*nex-*pre));
    }
}

void Del(int x)                         //删除操作; 
{
    multiset<int>::iterator it,pre,nex;
    pre=nex=it=val.find(x);             //找到x在val中迭代器变量的值,并将其赋为初值; 
    if(it!=val.begin()) //如果不在顶部,则在dta中删除和前一个值的差值; 
    {
        pre--;
        dta.erase(dta.find(*it-*pre));   
    }
    nex++;
    if(nex!=val.end())//如果不在底部,则在dta中删除和后一个值的差值; 
    {
        dta.erase(dta.find(*nex-*it));
        if(it!=val.begin())
            dta.insert(*nex-*pre);
    }
    val.erase(it);  //在val中也删除当前元素; 
}

int main()
{
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    readi(n);ans=n+1;
    for(int i=1;i<=n;i++)
        readi(a[i]);
    int l=1,r=0,v;
    while(l<n&&r<=n)
    {
        if(r==n)
            Del(a[l++]);
        else if(r<=l)
            Ins(a[++r]);
        else
        {
            v=*dta.begin();
            if(r-l+1>v)Del(a[l++]);
            else Ins(a[++r]);
        }
        if(l<r)
            ans=min(ans,max(r-l+1,*dta.begin()));
    }
    printf("%d\n",ans);
    return 0;
}

inline void readi(int &x)
{char c;while(c=getchar(),c<'0'||c>'9');
x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值