P3957 [NOIP2017 普及组] 跳房子

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 }

 

posted @ 2024-01-30 10:47  关于42号星球  阅读(34)  评论(0编辑  收藏  举报