Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)
Posted violet-acmer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)相关的知识,希望对你有一定的参考价值。
D 10248 修建高楼
题干
题目描述 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 ",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 ",resPos,resTot); 34 35 return 0; 36 }
以上是关于Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)的主要内容,如果未能解决你的问题,请参考以下文章
[NBA LIVE] 2018-2019赛季 最有价值球员之路 雷霆滚滚 活动攻略 v1.0
2018-2019赛季多校联合新生训练赛第三场(2018/12/8)补题题解
2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解