Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)

D 10248 修建高楼

D 传送门

题干

题目描述
    C 市有一条东西走向的“市河”。C 市的市长打算在“市河”的其中一条岸边自东往西的 n 个位置(可以将这 n 个位置看成在一条直线上,且位置不会重叠)依次建造高楼。
    C 市的设计部门设计了 T 个方案供市长挑选(方案编号为 1 到 T)。每个方案都提供了建造的每幢高楼的高度,自东向西依次为 h1,h2,h3,…,hn-1,hn。每幢楼房的高度在 1 到 n 之间(包括 1 和 n),且各不相同。
    市长在挑选设计方案时,喜欢 n 幢高楼中任意 3 幢(包括不连续的 3 幢)有一定的“梯度美”。所谓“梯度美”是指这 3 幢高楼满足:
第j幢的高度hj-第i幢的高度hi=第k幢的高度hk-第j幢的高度hj(1≤i<j<k≤n)
市长喜欢方案中这种“梯度美”现象越多越好。请编程帮市长挑选一下设计方案吧。 

输入
    T+1 行。
    第一行两个整数 T 和 n,分别表示设计部门提供的方案总数和打算建造的高楼数。
    接下来每一行表示一种方案。第 i+1 行表示第 i 种方案,每行 n 个整数,依次表示每幢高楼打算建造的高度。 

输出
输出共 1 行。
    包含两个整数,第一整数为出现“梯度美”次数最多的方案,第二个整数为对应方案“梯度美”出现的次数。如果出现“梯度美”次数最多的方案有多个,输出方案编号较小的方案。 

样例输入
2 5
3 1 2 4 5
3 1 2 5 4

样例输出
1 1

提示
    输入中共有2个方案,打算建造5幢高楼。
    第一个方案每幢高楼高度依次为3,1,2,4,5,其中第1幢,第4幢和第5幢高度出现“梯度美”(3,4,5),这3幢高楼的后一幢比前一幢依次高1。
    第二个方案每幢高楼高度依次为3,1,2,5,4,没有出现“梯度美”。
(1≤T≤50,且 3≤n≤2000)  

题解:

  考察知识点:模拟优化

    这道题,昨天下午考完试一直在看,看了好久好久,一直在找nlogn复杂度的算法(为什么要找nlogn复杂度的算法呢?因为我感觉,如果t=50,n=2000,那么

    就有1e6个楼房,而1e5的数据范围需要nlogn的时间复杂度,然后,就一直找不到在哪可以logn,呜呜呜~~~~)

    实属无奈,然后,就找老师要了一份标程,标程如下:

 1 #include<stdio.h>
 2 #include<string.h>
 3 int main()
 4 {
 5     int t,n,a[2005],ans=-1,ans1=0,b[10005]= {0},c;
 6     scanf("%d%d",&t,&n);
 7     for(int q=0; q<t; q++)
 8     {
 9         memset(b,0,sizeof(b));
10         c=0;
11         for(int i=0; i<n; i++)
12         {
13             scanf("%d",&a[i]);
14             b[a[i]+4000]=i;
15         }
16         for(int i=0;i<n-2;i++)
17             for(int j=i;j<n-1;j++)
18             if(b[2*a[j]-a[i]+4000]>j)
19             c++;
20         if(c>ans)
21             ans1=q,ans=c;
22     }
23     printf("%d %d",ans1+1,ans);
24     return 0;
25 }

    照着标程理解了一下,具体做法是枚举i,j楼的高度,判断是否存在满足条件的k楼,是个O(n^2)的复杂度,很纳闷,这怎么能过呢?????

  其实,在找老师要标程前,在ACM的群里问了一下,一个初三大佬,五分钟敲出的这道题,一发AC,这,这也太厉害了吧%%%%%%%

  差距太大了

  之所以要他写代码,是因为,标程里将memset()放到了循环内,然后,他说,将memset()放循环里很不好,有时候会因此而超时,然后,没有然后了。。。

  巨巨代码:

 1 #include <cstdio>
 2 using namespace std;
 3
 4 int hi[2005];
 5 int pos[4005];
 6
 7 int main()
 8 {
 9     int t,n;
10     scanf("%d%d",&t,&n);
11
12     int ans = 0;
13     int ansp = 1;
14     for(int l=1; l<=t; ++l)
15     {
16         for(int i=1; i<=n; ++i)
17             scanf("%d",hi+i);
18
19         for(int i=1; i<=n; ++i)
20             pos[hi[i]<<1] = i;
21
22         int curans = 0;
23         for(int i=1;i <= n-2;++i)
24             for(int j=i+2;j <= n;++j)
25                 if(i<pos[hi[i]+hi[j]] && pos[hi[i]+hi[j]]<j)
26                     ++curans;
27
28         if(curans>ans)
29         {
30             ans = curans;
31             ansp =  l;
32         }
33     }
34     printf("%d %d\n",ansp,ans);
35
36     return 0;
37 }

  具体思路是,枚举i,k,判断有没有满足条件的 j 。

  偷偷把他的代码改成我的风格,哈哈哈

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=2000+10;
 5
 6 int t,n;
 7 int h[maxn];
 8 int pos[2*maxn];
 9
10 int Solve()
11 {
12     for(int i=1;i <= n;++i)
13         pos[h[i]<<1]=i;//2*h[j]的位置
14     int res=0;
15     for(int i=1;i <= n-2;i++)
16         for(int k=i+2;k <= n;++k)
17             if(pos[h[i]+h[k]] > i && pos[h[i]+h[k]] < k)//判断(i,k)之间有没有h[i]+h[k]
18                 res++;
19     return res;
20 }
21 int main()
22 {
23     scanf("%d%d",&t,&n);
24     int resTot=0,resPos=1;
25     for(int kase=1;kase <= t;++kase)
26     {
27         for(int i=1;i <= n;++i)
28             scanf("%d",h+i);
29         int res=Solve();
30         if(resTot < res)
31             resTot=res,resPos=kase;
32     }
33     printf("%d %d\n",resPos,resTot);
34
35     return 0;
36 }

原文地址:https://www.cnblogs.com/violet-acmer/p/10090543.html

时间: 2024-10-09 20:30:18

Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)的相关文章

2018-2019赛季多校联合新生训练赛第六场(2018/12/15)补题题解

A 价钱统计(基础编程能力) 这个考点还是比较个性的,怎么四舍五入 解法 常规的讲如果四舍五入整数位的话,那么只需要在后面加个0.5然后强制转换一下就可以了 这个却要我们保留一位小数的四舍五入,那该怎么做呢 实际上我们只需要把这个数乘以10然后加0.5,强制转换后再除以10就可以了 代码 #include <bits/stdc++.h> using namespace std; double trans(double a) { a*=10; a+=0.5; a=int(a); a/=10; r

2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解

感慨 这次有点感冒,昏迷程度比较大中途还溜了 感谢 感谢qut的同学的帮助!!! A 小X与三角形(数学) 公式 两边的和-两边的差-1 因为边最小得大于两边的差,边最大得小于两边的和所以说求得是一个开区间内元素的个数 代码 #include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); ll a,

迎接2019多校联合新生训练赛(2018/12/31)

A 新年礼物(数学) 这个题之前cf div2刚刚考过应该都会吧.就是把左边界×2遍历一下就可以了 代码 #include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); ll l,r,sum=0; cin>>l>>r; for(ll i=l;i<=r;) i*=2,su

2018.12.2 中国石油大学第一次新生训练赛题解

整理人: 周翔 A题:李继朋 B题:李继朋 H题:魏斯博 原文地址:https://www.cnblogs.com/QLU-ACM/p/10057831.html

2019个人训练赛第二场-A - BowWow and the Timetable

题意: 大概就是给你一串二进制的数,然后让你求log(4)s吧,刚开始找错方向,先把它转成十进制,结果数太大 解决方法: 大概是分析这个数如果正好是4的幂次方的话在二进制的表示里应该只有一个1,所以分析数的长度就可以 #include<bits/stdc++.h> using namespace std; int main(){ string s; cin>>s; for(int i=1;i < s.size();i++){ if(s[i] == '1'){ cout<

HDU 4864 Task (贪心+STL多集(二分)+邻接表存储)(杭电多校训练赛第一场1004)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4864 解题报告:有n台机器用来完成m个任务,每个任务有一个难度值和一个需要完成的时间,每台机器有一个可以工作的最长时间和一个可以完成的任务的难度的最大值, 一台机器能完成一个任务的条件是这台机器的最长工作时间和能完成任务的难度值必须都大于等于这个任务,而且一台机器最多完成一个任务,假设一个任务的时间为t,难度值为x,那么完成这个任务可以赚到的钱 money = 500 * t + 2 * x; 现在

郑州大学2018新生训练赛第十场题解

比赛(补题)地址:http://222.22.65.164/problemset.php 题号为:4305 -- 4309 总述:这次新生赛难度偏于平和,但涵盖方面甚广,其中一道签到题是c语言题,并且有两道是hdu一百题的原题,一道简单的最小生成树,唯一"有些难度"的应该是一道数论题(毕竟本来自己就是搞数学的).   A.沙漠骆驼 这是一道经典的递推问题,原型为HDU 2044的"一只小蜜蜂-".思路很简单,以第5个沙丘为例,到达第五个沙丘的方式有两种:从第3个向

2018年全国多校算法寒假训练

题目描述 夫夫有一天对一个数有多少位数感兴趣,但是他又不想跟凡夫俗子一样,所以他想知道给一个整数n,求n!的在8进制下的位数是多少位. 输入描述: 第一行是一个整数t(0<t<=1000000)(表示t组数据)接下来t行,每一行有一个整数n(0<=n<=10000000) 输出描述: 输出n!在8进制下的位数. 示例1 输入 3 4 2 5 输出 2 1 3 思路: 斯特林公式. 斯特林公式(Stirling's approximation)是一条用来取n的阶乘的近似值的数学公式,

2019 HDU 多校赛第二场 HDU 6598 Harmonious Army 构造最小割模型

题意: 有n个士兵,你可以选择让它成为战士还是法师. 有m对关系,u和v 如果同时为战士那么你可以获得a的权值 如果同时为法师,你可以获得c的权值, 如果一个为战士一个是法师,你可以获得b的权值 问你可以获得的最大权值是多少? 题解: 对每个士兵建立一个点x ,点x 向源点s 连一条边,向汇点t 连一条边, 分别表示选择两种职业,然后就可以先加上所有的贡献,通过两点关系用 最小割建模,如下图所示 设一条边的三种贡献为A, B, C,可以得到以下方程: 如果x,y都是法师,你可以获得C的权值,但是