首页 > 其他分享 >CSP历年复赛题-P3957 [NOIP2017 普及组] 跳房子

CSP历年复赛题-P3957 [NOIP2017 普及组] 跳房子

时间:2024-06-09 11:55:34浏览次数:11  
标签:NOIP2017 跳房子 return int max mid long ans P3957

原题链接:https://www.luogu.com.cn/problem/P3957

题意解读:有n个格子,每个格子有不同的距离和分数,从起点,每次可跳距离为d,用g金币后可跳距离范围可以变成max(d-g,1) ~ d+g,

求最小的g,使得可跳跃得分不少于k。

解题思路:

1、单调性分析:

如果g越大,可跳跃的范围就越大,理论上能得的分数越多,因此可以通过二分g,来判断是否能得到k分,如果可以则继续缩小g,如果不行则放大g。

2、如何判断能否至少得k分:

联想到最大子段和,但这里没有必要连续,可以认为是最大子序列的和

设每次跳跃距离范围l = max(d-g,1), r = d+g

设x[i]表示i的距离,s[i]表示i的分数

设f[i]表示以i结尾的最大子序列的和,

f[i] = max(f[j] + s[i]),j取i-1 ~ 1,并且j的距离要在合理范围内

什么是合理范围?

如果x[j] + l > x[i],就不合理,因为从j跳不到i

如果x[j] + r < x[i],也不合理,同样从j跳不到i

以上算法的复杂度为O(n^2*logn)

先尝试编写代码,得到部分分!

80分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 500005;

int n, d, k;
int x[N], s[N];
long long f[N];

bool check(int g)
{
    int l = max(d - g, 1), r = d + g;
    memset(f, -0x3f, sizeof(f));
    f[0] = 0;
    for(int i = 1; i <= n; i++)
    {
        for(int j = i - 1; j >= 0; j--)
        {
            if(x[j] + l > x[i]) continue; //i要从1开始,因为第一个点也不一定能到
            if(x[j] + r < x[i]) break;
            f[i] = max(f[i], f[j] + s[i]);
            if(f[i] >= k) return true;
        }
    }
    return false;
}

int main()
{
    cin >> n >> d >> k;
    for(int i = 1; i <= n; i++) cin >> x[i] >> s[i];
    int l = 1, r = 1e9, ans = -1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    cout << ans;
    return 0;
}

如果数据增强,O(n^2*logn)理论上是无法通过的,需要进一步优化

3、单调队列优化

根据转移方程f[i] = max(f[j] + w[i])可知,i 只与一定范围内的j有关,且只和最大的f[j]有关,因此可以通过单调队列快速得到i之前有效范围内的最大f[j]

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 500005;

int n, d, k;
int x[N], s[N];
long long f[N];

bool check(int g)
{
    int l = max(d - g, 1), r = d + g;
    memset(f, -0x3f, sizeof(f));
    deque<int> q; //优先队列
    f[0] = 0;
    int j = 0; //j用来枚举i前面所有数,入队
    for(int i = 1; i <= n; i++)
    {
        //枚举所有j,去尾,入队
        while(x[j] + l <= x[i]) //j的位置+最小跳跃距离不能超过i
        {
            while(!q.empty() && f[q.back()] <= f[j]) q.pop_back();
            q.push_back(j);
            j++;
        }
        //去头
        while(!q.empty() && x[q.front()] + r < x[i]) q.pop_front();
        //计算
        if(!q.empty()) f[i] = f[q.front()] + s[i];

        if(f[i] >= k) return true;
    }
    return false;
}

int main()
{
    cin >> n >> d >> k;
    for(int i = 1; i <= n; i++) cin >> x[i] >> s[i];
    int l = 1, r = 1e9, ans = -1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    cout << ans;
    return 0;
}

 

标签:NOIP2017,跳房子,return,int,max,mid,long,ans,P3957
From: https://www.cnblogs.com/jcwy/p/18239405

相关文章

  • CSP历年复赛题-P3956 [NOIP2017 普及组] 棋盘
    原题链接:https://www.luogu.com.cn/problem/P3956题意解读:计算从(1,1)走到(m,m)的最小花费,有几个限定:同色格子可以走,花费为0;不同色格子可以走,花费为1;有色格子可以走到无色格子,花费为2,且用将无色格子临时染色;无色格子不能走到无色格子。解题思路:可以采用DFS来暴搜所有路径,需......
  • CSP历年复赛题-P3955 [NOIP2017 普及组] 图书管理员
    原题链接:https://www.luogu.com.cn/problem/P3955题意解读:给出n个图书编号,q个需求码,找到后缀与需求码匹配的最小图书编号,没有输出-1。解题思路:先对图书编号排序,用枚举法遍历每一个图书编号,看后缀是否与需求码相同。100分代码:#include<bits/stdc++.h>usingnamespacestd;c......
  • 【NOIP2017普及组复赛】题2:图书管理员
    题2:图书管理员【题目描述】图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个正整数。每位借书的读者手中有一个需求码,这个需求码也是一个正整数。如果一本书的图书编码恰好以读者的需求码结尾,那么这本书就是这位读者所需要的。小......
  • P3953 [NOIP2017 提高组] 逛公园
    P3953[NOIP2017提高组]逛公园求有向图中\(1\)到\(n\)的路径中长度小于等于\(dis(1,n)+k\)的方案数。\(dis(1,n)\)表示最短路。\(k\le50\)。部分分\(k=0\),直接最短路计数即可。我们发现有向图中存在后效性,不好动态规划,但我们仔细思考后,在不存在\(0\)边的情况下,设......
  • P3956 [NOIP2017 普及组] 棋盘
    /*这题本身不难,但是我写难了就是一个bfs,没了但是我的写法恰好犯了一个错误hark数据35110211311220330答案是4而我能输出30-1-110-11-10原因是我先走到了(2,2)这时候......
  • [题解] <NOIP2017> 时间复杂度
    [题解]NOIP2017时间复杂度题目描述小明正在学习一种新的编程语言A++,刚学会循环语句的他激动地写了好多程序并给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序,于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正......
  • P3956 [NOIP2017 普及组] 棋盘
    原题链接题解dijkstra算法的应用。相同颜色权值为0;不同颜色权值为1;有颜色到无颜色权值为2。其中不能连续两步走无颜色结点,即该情况需要特别考虑。code #include<bits/stdc++.h>usingnamespacestd;constintMAX=1e9;inta[105][105],dis[105][105],vis[105][105];int......
  • [NOIP2017 提高组] 小凯的疑惑 / [蓝桥杯 2013 省] 买不到的数目
    这肯定是学证明了,看这篇文章补充一下细节首先,\(m\)的范围应该是\([0,b-1]\)然后,当\(m\)取不同值的时候,\(ma\)%\(b\)一定为不同值(这个性质确实有点奇特,可以记下来)反证,如果\(m_1a\equivm_2a\:(mod\:b)\)且\(0≤m_1<m_2≤b-1\),那么就有\(b|(m_2-m_1)a\),题目给出了\(a,b\)互质,......
  • P3957 [NOIP2017 普及组] 跳房子
    原题链接题解二分加动态维护区间最大值注意设立变量的含义,改变变量值的规则code#include<bits/stdc++.h>#definelllonglongusingnamespacestd;llsum[500005]={0};structunit{llx,v;booloperator<(constunit&b)const{returnb.v>v;}//}room[5000......
  • P3958 [NOIP2017 提高组] 奶酪
    原题链接思路并查集然后看看是否存在上表面联通的洞与下表面联通的洞位于同一集合code#include<bits/stdc++.h>usingnamespacestd;doublen,h,r;intfa[1005];vector<int>up,down;struct{doublex,y,z;}hole[1005];doubledis(inti,intj){returnpo......