冲刺Noip2017模拟赛4 解题报告——五十岚芒果酱
题1 韬韬抢苹果(apple)
【问题描述】 又到了收获的季节,树上结了许多韬韬,错了,是许多苹果,有很多个小韬韬都来摘苹 果。每个韬韬都想要最大的苹果,所以发生了争执,为了解决他们的矛盾,出题人定了一项 特殊的规则,按体重的大小来定顺序,每一轮都是先由胖的先摘(照顾胖子),每个韬韬都 是很聪明的,不会错过眼前最大的苹果。现在问题来了,一共有 n 个苹果,m 个韬韬,要你 按原顺序输出每个韬韬可以抢到的苹果的总大小。 【输入格式】apple.in 第一行两个数 n,m。 接下来一行 n 个数,分别为每个苹果的大小。 接下来一行 m 个数,分别为每个韬韬的体重。 【输出格式】apple.out 一行 m 个数,每个韬韬抢到的苹果的大小。 【输入样例】 5 3 1 2 3 4 5 1 2 3 【输出样例】 3 5 7 【 数据规模 】 n,m<=100000
tag:模拟
思路:模拟即可,为了防止被极端数据卡开了long long。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cmath> 6 #define ll long long 7 #define maxn 100010 8 using namespace std; 9 ll ans[maxn]; 10 int ap[maxn],po,n,m; 11 struct TT{ 12 int w,id; 13 }tt[maxn]; 14 bool cmp1(int x,int y) 15 { 16 return x>y; 17 } 18 bool cmp2(TT x,TT y) 19 { 20 return x.w>y.w; 21 } 22 int main() 23 { 24 //freopen("apple.in","r",stdin); 25 //freopen("apple.out","w",stdout); 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=n;++i) scanf("%d",&ap[i]); 28 for(int i=1;i<=m;++i){ 29 scanf("%d",&tt[i].w); 30 tt[i].id=i; 31 } 32 sort(ap+1,ap+n+1,cmp1); 33 sort(tt+1,tt+m+1,cmp2); 34 int f=po=1; 35 while(1){ 36 for(int i=1;i<=m;++i){ 37 ans[tt[i].id]+=ap[po++]; 38 if(po>n){ 39 f=0; 40 break; 41 } 42 } 43 if(!f) break; 44 } 45 for(int i=1;i<=m;++i) cout<<ans[i]<<" "; 46 return 0; 47 }
题2 开场舞蹈(dance)
【问题描述】 在全世界人民的期盼下,2008 年北京奥林匹克运动会终于隆重召开了! 为了展示中华民族博大精深的优秀传统文化,负责开幕式开场舞蹈的编排人员一丝不 苟,每一个细节都力争完美。关于队伍是采用“天圆”阵还是“地方”阵的问题,大家讨论 了七天七夜,仍没有结果。于是,他们希望借助计算机,计算两种阵型的成本。 队伍将排列在一个二维平面内,且必须以(0,0)点为中心使得队伍保持对称美。“天 圆”阵是一个圆形,而“地方”阵则是一个边平行于坐标轴的正方形。由于某种因素,阵型 要求覆盖某些点(可以在边上)。 你的任务是,计算出能够覆盖这些点的两种阵型的最小面积。 【输入文件】 输入文件 dance.in。第一行是一个整数 n(1<=n<=100000),表示需要覆盖的点的个数。 接下来 n 行,第 i 行是两个整数 xi,yi(-1000<=xi,yi<=1000),表示第 i 个点的坐标位 置(xi,yi)。 【输出文件】 输出文件 dance.out。第一行是一个整数 s1,表示能够覆盖这些点的“天圆”阵的最小 面积(pi=3.14,四舍五入)。第二行是一个整数 s2,表示能够覆盖这些点的“地方”阵的 最小面积。 【样例输入】 4 0 0 0 2 5 0 8 0 【样例输出】 201 256
tag:模拟
思路:取最大值,注意四舍五入的处理,乘10取整,再将mod10的结果与5比较。还有更简单的方法,加上0.5再取整。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cmath> 6 #define ll long long 7 #define maxn 100010 8 using namespace std; 9 const double pi=3.14; 10 int n,A,ans; 11 double R; 12 double cal(int x,int y){return sqrt((double)(x*x+y*y));} 13 int main() 14 { 15 //freopen("dance.in","r",stdin); 16 //freopen("dance.out","w",stdout); 17 int x,y; 18 scanf("%d",&n); 19 for(int i=1;i<=n;++i){ 20 scanf("%d%d",&x,&y); 21 R=max(R,cal(x,y)); 22 A=max(A,max(abs(x),abs(y))); 23 } 24 y=(int)(R*R*pi*10); 25 ans=y/10; 26 if(y%10>=5) ans++; 27 printf("%d\n",ans); 28 printf("%d\n",A*A*4); 29 return 0; 30 }
题3 架设电话线(phoneline)
【 问题描述 】 Farmer John 打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务。 于是,FJ 必须为此向电信公司支付一定的费用。 FJ 的农场周围分布着 N(1 <= N <= 1,000)根按 1..N 顺次编号的废弃的电话线杆,任意两 根电话线杆间都没有电话线相连。一共 P(1 <= P <= 10,000)对电话线杆间可以拉电话线,其 余的那些由于隔得太远而无法被连接。 第 i 对电话线杆的两个端点分别为 A_i、B_i,它们间的距离为 L_i (1 <= L_i <= 1,000,000)。数据中保证每对{A_i,B_i}最多只出现 1 次。编号为 1 的电话线杆已经接入了 全国的电话网络,整个农场的电话线全都连到了编号为 N 的电话线杆上。也就是说,FJ 的 任务仅仅是找一条将 1 号和 N 号电话线杆连起来的路径,其余的电话线杆并不一定要连入 电话网络。 经过谈判,电信公司最终同意免费为 FJ 连结 K(0 <= K < N)对由 FJ 指定的电话线杆。 对于此外的那些电话线,FJ 需要为它们付的费用,等于其中最长的电话线的长度(每根电 话线仅连结一对电话线杆)。如果需要连结的电话线杆不超过 K 对,那么 FJ 的总支出为 0。 请你计算一下,FJ 最少需要在电话线上花多少钱。 【输入格式】 * 第 1 行: 3 个用空格隔开的整数:N,P,以及 K * 第 2..P+1 行: 第 i+1 行为 3 个用空格隔开的整数:A_i,B_i,L_i 【输入样例】phoneline.in 5 7 1 1 2 5 3 1 4 2 4 8 3 2 3 5 2 9 3 4 7 4 5 6 【输入说明】 一共有 5 根废弃的电话线杆。电话线杆 1 不能直接与电话线杆 4、5 相连。电话线杆 5 不能直接与电话线杆 1、3 相连。其余所有电话线杆间均可拉电话线。电信公司可以免费为 FJ 连结一对电话线杆。 【输出格式】 * 第 1 行: 输出 1 个整数,为 FJ 在这项工程上的最小支出。如果任务不可能完成,输 出-1 【输出样例】phoneline.out 4 【输出说明】 FJ 选择如下的连结方案:1->3;3->2;2->5,这 3 对电话线杆间需要的电话线的长度分 别为 4、3、9。FJ 让电信公司提供那条长度为 9 的电话线,于是,他所需要购买的电话线的 最大长度为 4。
tag:二分、最短路
思路:由于对于路径的选择、寻找答案都有很大的不确定性,可以考虑二分答案x作划分免费和付费的分界线,它也是付费边的上限。如果选择的边比x大视作距离为1,否则距离为0,那么dis[n]就被赋予了新的意义——从点1到点n最少选择的大于x的边数,跑一遍SPFA再看dis[n]有没有超过k,大于k说明答案不成立,因为电话公司无论如何都要支付超过x的这么多边,要把上限提高使得dis[n]变小减轻电话公司的压力。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #define ll long long 8 #define maxn 100010 9 #define inf 1<<30 10 using namespace std; 11 int n,m,k,hl[1010],vis[1010],dis[1010],cnt,cs[20010]; 12 queue<int>Q; 13 struct X{ 14 int u,v,w,ne; 15 }e[20010]; 16 void add(int u,int v,int w) 17 { 18 e[++cnt].u=u; 19 e[cnt].v=v; 20 e[cnt].w=w; 21 e[cnt].ne=hl[u]; 22 hl[u]=cnt; 23 } 24 void spfa() 25 { 26 memset(dis,127/3,sizeof(dis)); 27 dis[1]=0; 28 vis[1]=1; 29 Q.push(1); 30 while(!Q.empty()){ 31 int u=Q.front(); 32 Q.pop(); 33 for(int i=hl[u];i;i=e[i].ne){ 34 int v=e[i].v; 35 if(dis[v]>dis[u]+cs[i]){ 36 dis[v]=dis[u]+cs[i]; 37 if(!vis[v]){ 38 vis[v]=1; 39 Q.push(v); 40 } 41 } 42 } 43 vis[u]=0; 44 } 45 } 46 bool div2(int x) 47 { 48 memset(cs,0,sizeof(cs)); 49 for(int i=1;i<=n;++i) 50 for(int j=hl[i];j;j=e[j].ne) 51 if(e[j].w>x) cs[j]=1; 52 spfa(); 53 return dis[n]<=k; 54 } 55 bool cmp(int x,int y){ 56 return x>y; 57 } 58 int main() 59 { 60 //freopen("phoneline.in","r",stdin); 61 //freopen("phoneline.out","w",stdout); 62 int x,y,w; 63 scanf("%d%d%d",&n,&m,&k); 64 for(int i=1;i<=m;++i){ 65 scanf("%d%d%d",&x,&y,&w); 66 add(x,y,w); 67 add(y,x,w); 68 } 69 int l=0,r=1000001; 70 while(l<r){ 71 int mid=(l+r)>>1; 72 if(div2(mid)) r=mid; 73 else l=mid+1; 74 } 75 r==1000001?printf("-1"):printf("%d\n",r); 76 return 0; 77 }
题4 洪水(slikar)
【问题描述】 一天,一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安全 的。 森林的地图由 R 行 C 列组成,空白区域用点“.”表示,洪水的区域用“*”表示,而 岩石用“X”表示,另画家的住所用“D”表示,画家用“S”表示。 有以下几点需要说明: 1.每一分钟画家能向四个方向移动一格(上、下、左、右) 2.每一分钟洪水能蔓延到四个方向的相邻格子(空白区域) 3.洪水和画家都不能通过岩石区域 4.画家不能通过洪水区域(同时也不行,即画家不能移到某个格子,该格子在画家达到 的同时被洪水蔓延到了,这也是不允许的) 5. 洪水蔓不到画家的住所。 给你森林的地图,编写程序输出最少需要花费多长时间才能从开始的位置赶回家中。 【输入】 输入第一行包含两个整数 R 和 C(R,C<=50)。 接下来 R 行每行包含 C 个字符(“.”、“*”、“X”、“D”或“S”)。地图保证只有一个“D” 和一个“S”。 【输出】 输出画家最快安全到达住所所需的时间,如果画家不可能安全回家则输出“KAKTUS”。 【输入输出样例 1 】 slikar.in slikar.out 3 3 D.* ... .S. 3 【输入输出样例 2 】 slikar.in slikar.out 3 3 D.* ... ..S KAKTUS 【输入输出样例 3 】 slikar.in slikar.out 3 6 D...*. .X.X.. ....S. 6
tag:模拟/dfs、bfs/最短路
思路:初始化所有点洪水出现的时间为无穷大,以每个“*”作基点向外dfs预处理更新时间(能取到最小值再扩展,此处算是剪枝),之后bfs走迷宫,到达的时间一定要先于洪水出现的时间,也可以二维转一维跑SPFA。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #define ll long long 8 #define maxn 2510 9 #define inf 707406378 10 using namespace std; 11 int dx[]={0,1,0,-1},dy[]={1,0,-1,0},n,m,cnt,dis[maxn],hl[maxn],MP[maxn],S,T,vis[maxn]; 12 char mp[60][60]; 13 queue<int>Q; 14 struct X{ 15 int u,v,w,ne; 16 }e[maxn*4]; 17 void add(int u,int v) 18 { 19 e[++cnt].u=u; 20 e[cnt].v=v; 21 e[cnt].ne=hl[u]; 22 hl[u]=cnt; 23 } 24 int cal(int x,int y){return (x-1)*m+y;} 25 bool ok(int x,int y) 26 { 27 if(x>=1&&x<=n&&y>=1&&y<=m) return true; 28 return false; 29 } 30 void dfs(int x,int y,int t) 31 { 32 if(!t||(ok(x,y)&&mp[x][y]=='.'&&t<MP[cal(x,y)])){ 33 MP[cal(x,y)]=t; 34 for(int i=0;i<4;++i) dfs(x+dx[i],y+dy[i],t+1); 35 } 36 } 37 bool spfa() 38 { 39 dis[S]=0; 40 vis[S]=1; 41 Q.push(S); 42 while(!Q.empty()){ 43 int u=Q.front(); 44 Q.pop(); 45 for(int i=hl[u];i;i=e[i].ne){ 46 int v=e[i].v,aft=dis[u]+1; 47 if(dis[v]>aft&&MP[v]>aft){ 48 dis[v]=aft; 49 if(!vis[v]){ 50 vis[v]=1; 51 Q.push(v); 52 } 53 } 54 } 55 vis[u]=0; 56 } 57 if(dis[T]==inf) return false; 58 return true; 59 } 60 int main() 61 { 62 //freopen("slikar.in","r",stdin); 63 //freopen("slikar.out","w",stdout); 64 memset(dis,127/3,sizeof(dis)); 65 memset(MP,127/3,sizeof(MP)); 66 scanf("%d%d",&n,&m); 67 for(int i=1;i<=n;++i) 68 for(int j=1;j<=m;++j) 69 scanf(" %c",&mp[i][j]); 70 for(int i=1;i<=n;++i) 71 for(int j=1;j<=m;++j){ 72 if(mp[i][j]=='*') dfs(i,j,0); 73 else{ 74 switch(mp[i][j]){ 75 case 'S':S=cal(i,j);break; 76 case 'D':T=cal(i,j);break; 77 case 'X':continue;break; 78 } 79 for(int k=0;k<4;++k){ 80 int X=i+dx[k],Y=j+dy[k],t=1; 81 if(ok(X,Y)&&mp[X][Y]!='*'&&mp[X][Y]!='X') add(cal(i,j),cal(X,Y)); 82 } 83 } 84 } 85 if(!spfa()) puts("KAKTUS"); 86 else printf("%d\n",dis[T]); 87 return 0; 88 }
————————今天好晚了懒得粘分割线呢————————
芒果君:表示这次终于没有翻车,没有预计结果因为害怕这么多模拟写炸,最后还挺高的,开森,不过以后还是要多刷图论啊。