P1020 [NOIP1999 提高组] 导弹拦截

本文讲述了作者在解决洛谷竞赛P1020导弹拦截问题时遇到的超时问题,涉及二分法求解最长不递增子序列的代码实现,并对数组访问优化进行分析。

网址如下:

P1020 [NOIP1999 提高组] 导弹拦截 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

怪,实在是怪

怎么会出现在自家电脑运行时间无限接近于0,在洛谷测试的时候超时的情况

在洛谷的o2优化中,是说我的数组访问越界了

但是看不出来哪里有

测试点1的运行时间:

最下面的,接近于0

在洛谷上的:

代码如下:

#include<stdio.h>
#include<ctype.h>
void scanf_line(void);
int dic(int l, int u, int hi);
int dic_2(int l, int u, int hi);
int dp[100001], f[100001], num[100001], g[100001];
int len, maxn = 1, minn = 1;

int main(void)
{
    //输入
    scanf_line();
    //求最长不递增子序列
    f[1] = g[1] = num[1];
    for(int i = 2; i <= len; i++)
    {
        //二分法求fx最逼近hi时的x,更新dp以及f,maxn
            //初始时的意外情况
            if(f[1] <= num[i])  dp[i] = 1, f[1] = num[i];
            else if(f[maxn] >= num[i])dp[i] = ++maxn, f[maxn] = num[i];
            //正常情况
            else
            {
                dp[i] = dic(1, maxn, num[i]) + 1;
                f[dp[i]] = num[i];
            }
        //二分法求此时的minn值并更新g
            //初始时的意外情况
            if(g[1] > num[i])  g[1] = num[i];
            else if(g[minn] < num[i])  g[++minn] = num[i];
            //正常情况
            else  g[dic_2(1, minn, num[i])] = num[i];
    }
    //输出
    printf("%d\n%d", maxn, minn);

    return 0;
}
void scanf_line(void)
{
    int ext = 0;
    for(char c; (c = getchar()) != '\n'; )
        if(isdigit(c))
            ext = ext * 10 + c - '0';
        else
            num[++len] = ext, ext = 0;
    num[++len] = ext;
    return;
}
int dic(int l, int u, int hi)
{
    if(u - l <= 1)  return l;

    int mid = (l + u) / 2;
    if(f[mid] < hi)  return dic(l, mid, hi);
    else if(f[mid] > hi)  return dic(mid, u, hi);
    else  return mid;
}
int dic_2(int l, int u, int hi)
{
    if(u - l <= 1)  return u;

    int mid = (l + u) / 2;
    if(g[mid] < hi)  return dic_2(mid, u, hi);
    else if(g[mid] > hi)  return dic_2(l, mid, hi);
    else  return mid;
}

参考的题解:

题解 P1020 【[NOIP1999 普及组] 导弹拦截】 - 古明地觉世界第一! - 洛谷博客 (luogu.com.cn)

于2025/2/22添加:

上次做这题的时候是2024/1/22,一年多了

最近在狂刷dp题,刚好推荐的题目里面有之前这个在洛谷那没过的题,就回来做了一下

以下为AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 100010;
int f[maxn]{0x3f3f3f3f}, ans, ans2 = 0;
int q[maxn];

int main(void)
{
    int val; memset(q, 0x3f, sizeof(q));
    while(~scanf("%d", &val)){
        int l = 0, r = ans;
        while(l < r){
            int mid = (l + r + 1) >> 1;
            if(f[mid] >= val) l = mid; else r = mid - 1;
        }
        f[l + 1] = val; ans = max(ans, l + 1);
        //求解第二问
        l = 0, r = ans2;
        while(l < r){
            int mid = (l + r) >> 1;
            if(q[mid] >= val) r = mid; else l = mid + 1;
        }
        q[l] = val; if(l == ans2) ans2++;
    }
    printf("%d\n%d", ans, ans2);

    return 0;
}

回头看过去,发现我的代码的风格变了好多,常用语言也从C变成C++了

唉,时间真快,大学四年过了快一半了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值