首页 > 其他分享 >P3957 [NOIP2017 普及组] 跳房子

P3957 [NOIP2017 普及组] 跳房子

时间:2024-01-30 10:57:47浏览次数:33  
标签:NOIP2017 跳房子 ll int sum long 500010 include P3957

50分代码

 1 //P3957 [NOIP2017 普及组] 跳房子
 2 #include<iostream>
 3 #include<queue>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 int n,d,k;
 9 int a[500010][2];
10 ll f[500010],sum=0;
11 bool check(int g) {
12     int l=max(1,d-g),r=d+g;
13     //cout<<"%%%"<<l<<' '<<r<<endl;
14     memset(f,-127,sizeof f);
15     f[0]=0;
16     for(int i=1; i<=n; i++) { //每个格子
17         int td;
18         for(int j=0; j<i; j++) { //当前格子的前面格子,从小到大去寻找 
19             td=a[i][0]-a[j][0];
20             //cout<<"***"<<j<<" "<<td<<endl;
21             if(td>=l&&td<=r) {
22                 f[i]=max(f[i],f[j]+a[i][1]);
23             }
24             if(f[i]>=k) return true;
25             if(td<l) break;
26         }
27     //    cout<<i<<' '<<f[i]<<endl;
28     }
29     return false;
30 }
31 
32 int main() {
33     scanf("%d %d %d",&n,&d,&k);
34     for(int i=1; i<=n; i++) {
35         scanf("%d %d",&a[i][0],&a[i][1]);
36         if(a[i][1]>0) sum+=a[i][1];
37     }
38     if(sum<k) { //所有的正分加起来都不够希望获得的分数
39         printf("-1");
40         return 0;
41     }
42     //二分
43     int l=0,r=max(0,a[n][0]-d);
44     while(l<r) {
45         //cout<<'*'<<l<<' '<<r<<endl;
46         int mid=(l+r)/2;
47         if(check(mid)) r=mid;
48         else l=mid+1;
49     }
50     printf("%lld",l);
51     return 0;
52 }

80分代码

18行,显然我们要取得更大的f[i]的值。而i越大,f[i]的值更大的可能性更高,所以可以从大到小去寻找。但是并不严谨,只是可能性更高一些。

//P3957 [NOIP2017 普及组] 跳房子
#include<iostream>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,d,k;
int a[500010][2];
ll f[500010],sum=0;
bool check(int g) {
    int l=max(1,d-g),r=d+g;
    //cout<<"%%%"<<l<<' '<<r<<endl;
    memset(f,-127,sizeof f);
    f[0]=0;
    for(int i=1; i<=n; i++) { //每个格子
        int td;
        for(int j=i-1; j>=0; j--) { //当前格子的前面格子,从大到小寻找 
            td=a[i][0]-a[j][0];
            //cout<<"***"<<j<<" "<<td<<endl;
            if(td>=l&&td<=r) {
                f[i]=max(f[i],f[j]+a[i][1]);
            }
            if(f[i]>=k) return true;
            if(td>r) break;
        }
        //    cout<<i<<' '<<f[i]<<endl;
    }
    return false;
}

int main() {
    scanf("%d %d %d",&n,&d,&k);
    for(int i=1; i<=n; i++) {
        scanf("%d %d",&a[i][0],&a[i][1]);
        if(a[i][1]>0) sum+=a[i][1];
    }
    if(sum<k) { //所有的正分加起来都不够希望获得的分数
        printf("-1");
        return 0;
    }
    //二分
    int l=0,r=max(0,a[n][0]-d);
    while(l<r) {
        //cout<<'*'<<l<<' '<<r<<endl;
        int mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%lld",l);
    return 0;
}

100分代码

显然18行去求f[i],可以用更快的方式。用两个指针,直接指向能够跳跃的区间。

 1 //P3957 [NOIP2017 普及组] 跳房子
 2 #include<iostream>
 3 #include<queue>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 int n,d,k;
 9 int a[500010][2];
10 ll f[500010],sum=0;
11 bool check(int g) {
12     int l=max(1,d-g),r=d+g;
13     //cout<<"%%%"<<l<<' '<<r<<endl;
14     memset(f,-127,sizeof f);
15     f[0]=0;
16     int pl=0,pr=0; //两端
17     for(int i=1; i<=n; i++) { //每个格子
18         while(a[i][0]-a[pl][0]>r) pl++;
19         while(a[i][0]-a[pr][0]>=l) pr++;
20         for(int j=pr-1; j>=pl; j--) {
21             f[i]=max(f[i],f[j]+a[i][1]);
22             if(f[i]>=k) return true;
23         }
24     }
25     return false;
26 }
27 
28 int main() {
29     scanf("%d %d %d",&n,&d,&k);
30     for(int i=1; i<=n; i++) {
31         scanf("%d %d",&a[i][0],&a[i][1]);
32         if(a[i][1]>0) sum+=a[i][1];
33     }
34     if(sum<k) { //所有的正分加起来都不够希望获得的分数
35         printf("-1");
36         return 0;
37     }
38     //二分
39     int l=0,r=max(0,a[n][0]-d);
40     while(l<r) {
41         //cout<<'*'<<l<<' '<<r<<endl;
42         int mid=(l+r)/2;
43         if(check(mid)) r=mid;
44         else l=mid+1;
45     }
46     printf("%lld",l);
47     return 0;
48 }

 

标签:NOIP2017,跳房子,ll,int,sum,long,500010,include,P3957
From: https://www.cnblogs.com/mantou20210331/p/17996583

相关文章

  • 算法题:跳房子问题(爬楼梯问题进阶) 求解受限制情况下的方案数目
    问题跳房子,规定总共有n个格子,每次可以选择跳1个格子、2个格子或3个格子,但是下一步不能和当前选择的跳跃距离一样,计算总共有多少种跳房子方案。分析这就是经典爬楼梯问题的进阶,仅仅换了个说法,但是比经典的爬楼梯问题难了不少,传统的爬楼梯问题一次可以上1或2个台阶没有连续动作......
  • P3953 [NOIP2017 提高组] 逛公园
    Description策策同学特别喜欢逛公园。公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有自环和重边。其中\(1\)号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。策策每天都会去逛公园,他总是从\(1\)号点进去,从\(N\)......
  • P3956 [NOIP2017 普及组] 棋盘
    传送门P3956[NOIP2017普及组]棋盘不清楚曾师为什么把这个神奇的题目放在搜索\(search\)专栏,反正我用\(dijkstra\)水过去了,虽然\(dijkstra\)严格来说也是一种能够解决一般性最短路问题的算法。然后考虑这道题的建图。这道题来看首先是去除魔法的部分,一般地,任意一个点只......
  • NOIP2017提高组初赛易错题解析
     8.由四个不同的点构成的简单无向连通图的个数是()A.32 B.35 C.38 D.41错误原因:数重了正解:分情况计算,6条边的有1种,5条边的有C(6,1)=6种,4条边的有C(6,4)=15种,3条边,要分度数,2+2+1+1的有12种,3+1+1+1的有4种,共38种 10.若 f0​=0,f1​=1,fn+1​=(fn​+fn−1)/2​​,则随着......
  • 「NOIP2017 普及组」棋盘 题解
    前言一个绿题,风光啊QwQ题面传送门思路怎么走我们定义一个函数dfs(x,y,coin,can,color)x,y表示坐标,coin表示当前的金币数量,color表示当前坐标的颜色,can表示当前是否能施展魔法。再加一个mp数组记录颜色,-1表示无颜色,0表示红色,1表示黄色为什么不直接使用mp[x][y]获取颜......
  • 6312: 河中跳房子 二分
    描述 每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一个岩石跳到另一个岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点L远(1≤L≤1,000,000,000)的终点处均有一个岩石。在起点和终点之间,有N(0≤N≤50,000)个岩石,每个岩石与起点的距......
  • 【题解】[NOIP2017 提高组] 逛公园
    题目描述:策策同学特别喜欢逛公园。公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有自环和重边。其中\(1\)号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。策策每天都会去逛公园,他总是从\(1\)号点进去,从\(N\)号......
  • P3954 [NOIP2017 普及组] 成绩
    [NOIP2017普及组]成绩题目背景NOIP2017普及组T1题目描述牛牛最近学习了C++入门课程,这门课程的总成绩计算方法是:总成绩=作业成绩$\times20%+$小测成绩$×30%+$期末考试成绩$\times50%$牛牛想知道,这门课程自己最终能得到多少分。输入格式三个非负整数$A,B,C$,分别......
  • 算法刷题记录:[NOIP2017]图书管理员
    题目链接https://ac.nowcoder.com/acm/contest/19306/1050题目分析因为要求最小编号,并且该编号是以读者的编号结尾,这边直接排序+翻转,找开头的数。记录是因为看到某个大佬非常好的思路,直接对编号进行取模,就是末尾的数。如果想得到末尾的数,直接进行取模即可~~AC代码#include<......
  • NOIP2017普及组试题题解
    1.成绩原题:https://www.luogu.com.cn/problem/P3954代码:#include<bits/stdc++.h>#definelllonglongusingnamespacestd;inta,b,c;intmain(){ cin>>a>>b>>c; cout<<a/10*2+b/10*3+c/10*5; return0;}解题思路:因为数据保证a,b,c都是10的......