清北学堂D4

Posted 小蒟蒻

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了清北学堂D4相关的知识,希望对你有一定的参考价值。

Part1--模拟题

今天算是正常吧,120分。其中第一题100,第二题20,第三题不知道怎么运行时错误了。

(1)第一题

财富(treasure)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK有n个小伙伴。每个小伙伴有一个身高hi。

这个游戏是这样的,LYK生活的环境是以身高为美的环境,因此在这里的每个人都羡慕比自己身高高的人,而每个人都有一个属性ai表示它对身高的羡慕值。

这n个小伙伴站成一列,我们用hi来表示它的身高,用ai来表示它的财富。

每个人向它的两边望去,在左边找到一个最近的比自己高的人,然后将ai朵玫瑰给那个人,在右边也找到一个最近的比自己高的人,再将ai朵玫瑰给那个人。当然如果没有比自己身高高的人就不需要赠送别人玫瑰了。也就是说一个人会给0,1,2个人玫瑰(这取决于两边是否有比自己高的人)。

每个人都会得到若干朵玫瑰(可能是0朵),LYK想知道得了最多的玫瑰的那个人得了多少玫瑰。(然后嫁给他>3<)

输入格式(treasure.in)

    第一行一个数n表示有n个人。

    接下来n行,每行两个数hi,ai。

输出格式(treasure.out)

    一个数表示答案。

输入样例

3

4 7

3 5

6 10

输出样例

12

样例解释

第一个人会收到5朵玫瑰,第二个没人送他玫瑰,第三个人会收到12朵玫瑰。

数据范围

对于50%的数据n<=1000,hi<=1000000000。

对于另外20%的数据n<=50000,hi<=10。

对于100%的数据1<=n<=50000,1<=hi<=1000000000。1<=ai<=10000。

这道题从某种程度上来说是道一眼题。因为一眼就能看出O(n^2)的做法。但作为一个有追求的人,我还是认真的思考了一下有没有O(n)的办法,毕竟O(n^2)估计不能A。但后来也没想出来,所以就……嗯。

我的代码(没想到竟然拿满了,大概是数据有点弱):

技术分享
 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 long long a[50101],h[50101];
 9 long long sum[50101];
10 int main()
11 {
12     
13     freopen("treasure.in","r",stdin);
14     freopen("treasure.out","w",stdout);
15     
16     int n;
17     scanf("%d",&n);
18     long long minn=1000000005,maxn=0;
19     for(int i=1;i<=n;i++)
20     {
21         scanf("%lld%lld",&h[i],&a[i]);
22         minn=min(minn,h[i]);
23         maxn=max(maxn,h[i]);
24     }
25     for(int i=1;i<=n;i++)
26     {
27         if(a[i]==maxn) continue;
28         if(a[i]==minn) {sum[i-1]+=a[i];sum[i+1]+=a[i];continue;}
29         for(int j=i-1;j>0;j--)
30         {
31             if(h[j]>h[i]) {sum[j]+=a[i];break;}
32         }
33         for(int j=i+1;j<=n;j++)
34         {
35             if(h[j]>h[i]) {sum[j]+=a[i];break;}
36         }
37     }
38     long long ans=0;
39     for(int i=1;i<=n;i++) ans=max(ans,sum[i]);
40     printf("%lld",ans);
41     //system("pause");
42     return 0;
43 }
a

后来老师讲了O(n)的做法。然而好像有点没听懂……代码如下 :  @周老师

技术分享
 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 int n,s[50002],d[50002],ans[50002],ANS,a[50002],b[50002],r,i;
 8 //b[i]表示第i个人收到的玫瑰数
 9 //s[]单调队列 
10 //d[i]在单调的数列中第i个位置是n个人中的哪个人 
11 int main()
12 {
13     freopen("treasure.in","r",stdin);
14     freopen("treasure.out","w",stdout);
15     cin>>n;
16     for (i=1; i<=n; i++) scanf("%d%d",&a[i],&b[i]);
17     s[1]=a[1]; d[1]=1; r=1;
18     for (i=2; i<=n; i++)
19     {
20         while (r!=0 && a[i]>s[r]) {ans[i]+=b[d[r]]; r--; }  
21         r++;  //队列中元素+1 
22         s[r]=a[i];//推入单调队列 
23         d[r]=i;
24     }
25     s[1]=a[n]; d[1]=n; r=1;
26     for (i=n-1; i>=1; i--)
27     {
28         while (r!=0 && a[i]>s[r]) { ans[i]+=b[d[r]]; r--; }
29         r++;
30         s[r]=a[i];
31         d[r]=i;
32     }
33     for (i=1; i<=n; i++) ANS=max(ANS,ans[i]);
34     cout<<ANS;
35     return 0;
36 }
astd

(2)第二题

正方形(square)

Time Limit:1000ms   Memory Limit:128MB

题目描述

在一个10000*10000的二维平面上,有n颗糖果。

LYK喜欢吃糖果!并且它给自己立了规定,一定要吃其中的至少C颗糖果!

事与愿违,LYK只被允许圈出一个正方形,它只能吃在正方形里面的糖果。并且它需要支付正方形边长的价钱。

LYK为了满足自己的求食欲,它不得不花钱来圈一个正方形,但它想花的钱尽可能少,你能帮帮它吗?

输入格式(square.in)

    第一行两个数C和n。

    接下来n行,每行两个数xi,yi表示糖果的坐标。

输出格式(square.out)

    一个数表示答案。

输入样例

3 4

1 2

2 1

4 1

5 2

输出样例

4

样例解释

选择左上角在(1,1),右下角在(4,4)的正方形,边长为4。

数据范围

对于30%的数据n<=10。

对于50%的数据n<=50。

对于80%的数据n<=300。

对于100%的数据n<=1000。1<=xi,yi<=10000。

我就是两两的枚举端点,然后用这两个端点扩出一个最小的正方形,之后搜一遍里面有多少点。如果点数够了,就与当前的ans比较,保留小的。但是只过了两个点,其他的都结果错误。可能是因为我默认正方形的左上角(或右上角)有一颗糖框住,但其实不一定。

我的代码:

技术分享
 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 int n,C;
 9 int xz,yz,xy,yy;
10 int maxn;
11 struct point
12 {
13     int x,y;
14     bool operator <(const point&o)const
15     {
16         if(x<o.x) return true;
17         else if(x==o.x && y<o.y) return true;
18         else return false;
19     }
20 }a[1010];
21 void make_square(int i,int j)
22 {
23     maxn=0;
24     maxn=max(abs(a[j].y-a[i].y)+1,abs(a[j].x-a[i].x)+1);
25     //cout<<maxn<<endl;
26     if(a[i].y<=a[j].y) {xz=a[i].x;yz=a[i].y;xy=xz+maxn-1;yy=yz+maxn-1;}
27     else
28     {
29         xz=a[i].x;yz=a[i].y-maxn+1;
30         xy=a[i].x+maxn-1;yy=a[i].y;
31     }
32 }
33 bool check()
34 {
35     int cnt=0;
36     for(int i=1;i<=n;i++)
37     {
38         if(a[i].x>=xz && a[i].x<=xy && a[i].y>=yz && a[i].y<=yy) cnt++;
39         if(cnt>=C) break;
40     }
41     if(cnt>=C) return true;
42     else return false;
43 }
44 
45 int main()
46 {
47     freopen("square.in","r",stdin);
48     freopen("square.out","w",stdout);
49     scanf("%d%d",&C,&n);
50     for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
51     sort(a+1,a+n+1);
52     //for(int i=1;i<=n;i++) cout<<a[i].x<<" "<<a[i].y<<endl;
53     int ans=10005;
54     for(int i=1;i<n;i++)
55     {
56         for(int j=i+1;j<=n;j++)
57         {
58             make_square(i,j);
59             if(check()) ans=min(ans,maxn);
60         }
61     }
62     printf("%d",ans);
63     //system("pause");
64     return 0;
65 }
b

正解思路:

 


以上是关于清北学堂D4的主要内容,如果未能解决你的问题,请参考以下文章

清北学堂模拟赛d4t2 b

清北学堂国庆day2解题报告

2017清北学堂集训笔记——图论

清北学堂Day1

清北学堂(2019 4 30 ) part 3

清北学堂国庆day1解题报告