CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧。
T1 魔幻森林
描述
Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树,其中一些树上结有能够产生能量的魔力水果。已知每个水果的位置(Xi,Yi)以及它能提供的能量Ci。
然而,魔幻森林在某些时候会发生变化:
(1) 有两行树交换了位置。
(2) 有两列树交换了位置。
当然,树上结有的水果也跟随着树一起移动。不过,只有当两行(列)包含的魔力水果数都大于0,或者两行(列)都没有魔力水果时,上述变化才会发生。
Cortana对这些魔力水果很感兴趣,希望你帮她实时监测这片森林里魔力水果的情况。
输入格式
第一行包含3个整数N,M,K,分别表示矩阵的行数、列数和魔力水果的总数。
接下来K行每行三个整数X,Y,C,描述水果的位置(X,Y)和能量C。如果两个水果的位置相同,它们的能量累加。
第K+2行有一个整数T。
接下来T行每行三个整数Q,A,B:
若Q=1,表示A、B两行交换;
若Q=2,表示A、B两列交换;
若Q=3,表示询问位置(A,B)上产生的能量(没有水果视为0)。
1<=N,M<=2*10^9,0<=K,T<=10^5,0<=X,A<=N-1,0<=Y,B<=M-1,1<=C<=1000。
输出格式
对于每个询问,输出一个整数表示答案。
看到如此大的范围,果子又如此少,我一开始想到的是稀疏矩阵。然后思考如何交换。后来发现离散化即可。每次交换行或者交换列就将离散化后的坐标交换即可。用map实现,所有操作log(n),核心代码不超过20行
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <list> 12 #include <vector> 13 #include <ctime> 14 #include <functional> 15 #define pritnf printf 16 #define scafn scanf 17 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned int Uint; 21 const int INF=0x7ffffff; 22 //==============struct declaration============== 23 24 //==============var declaration================= 25 const int MAXN=100010; 26 map <int,int> R,C; 27 map <pair<int,int>,int> Fruits; 28 int row,col,k,q; 29 int rcnt=0,ccnt=0; 30 //==============function declaration============ 31 32 //==============main code======================= 33 int main() 34 { 35 scanf("%d%d%d",&row,&col,&k); 36 For(i,1,k){ 37 int r,c,v; 38 scanf("%d%d%d",&r,&c,&v); 39 if (R[r]==0) R[r]=++rcnt; 40 if (C[c]==0) C[c]=++ccnt; 41 Fruits[make_pair(R[r],C[c])]+=v; 42 } 43 scanf("%d",&q); 44 while (q--){ 45 int cmd,a,b; 46 scanf("%d%d%d",&cmd,&a,&b); 47 if (cmd==1){ 48 if (R[a]==0||R[b]==0) continue; 49 swap(R[a],R[b]); 50 } 51 else if (cmd==2){ 52 if (C[a]==0||C[b]==0) continue; 53 swap(C[a],C[b]); 54 } 55 else if (cmd==3){ 56 printf("%d\n",Fruits[make_pair(R[a],C[b])]); 57 } 58 } 59 60 return 0; 61 } 62 //================fuction code====================
T1代码
T2 过河
描述
有个青蛙要过河,河的横截面被看做一个数轴,河岸在0和M处。河里有N块石头,可以用数轴上(0,M)中的N个点表示。青蛙要从0跳到M,每步跳的距离不能超过L,并且必须落在石头上(不能跳进河里)。
以目前的石头数,青蛙有可能过不了河。Cortana想帮帮这只青蛙,但是又不想让它过河过得太容易(以免养成青蛙好吃懒做的坏习惯),于是决定往河里再添加一些石头,使得青蛙在能过河的前提下,过河需要跳的步数尽可能多。
由于这只青蛙也很机智,在Cortana放好石头以后,它总会采取最优策略(跳尽可能少的步数)过河。因此她Cortana要采取适当的方式放置石头,使青蛙的最优策略尽可能差。
输入格式
第一行3个正整数N、M、L。
第二行N个正整数Ai,描述河里已经有的石头的位置。
0<=N<=2*10^5,1<=M<=10^9,1<=L<=10^9,0<Ai<M。
输出格式
输出在Cortana添加一些石头后,过河的最优策略的步数最大是多少。
由于青蛙跳的步数没有下限,我们知道过河的最优策略一定是跳到能跳到的离当前石头最远的石头上,如果青蛙能够向前跳,那么没有必要增加石头。下面主要考虑不能够跳到的情况下如何加石头。
设当前位置是pos,上一步跳的距离为Laststep,在pos+L的范围内没有石头。显然加石头加的越近越好,我们考虑加石头在pos+L-Laststep+1的位置。
为什么?因为如果再向前1格,加在pos+L-Laststep的地方,青蛙会直接从pos-Laststep的地方直接跳到这里,而不会经过pos位。再向后一格的话解不会比当前格更优。
然后Laststep在每次跳动的时候进行修改。特别地,Laststep初始应该为l,这样青蛙如果出门的时候没办法直接跳到石头上就会跳至1。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <list> 12 #include <vector> 13 #include <ctime> 14 #include <functional> 15 #define pritnf printf 16 #define scafn scanf 17 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned int Uint; 21 const int INF=0x7fffffff; 22 //==============struct declaration============== 23 24 //==============var declaration================= 25 const int MAXN=2*100010; 26 int n,m,l; 27 int Stone[MAXN]; 28 //==============function declaration============ 29 30 //==============main code======================= 31 int main() 32 { 33 scanf("%d%d%d",&n,&m,&l); 34 For(i,1,n) 35 scanf("%d",Stone+i); 36 sort(Stone+1,Stone+1+n); 37 Stone[0]=0;Stone[n+1]=m;Stone[n+2]=INF; 38 int Laststep=l,pos=0,cnt=0; 39 while (Stone[pos]<m){ 40 int i; 41 for(i=1;Stone[i+pos]-Stone[pos]<=l;i++) 42 Laststep=Stone[i+pos]-Stone[pos]; 43 if (i!=1) 44 pos=pos+i-1; 45 else{ 46 Stone[pos]+=l-Laststep+1; 47 Laststep=l-Laststep+1; 48 } 49 cnt++; 50 //pritnf("%d ",Stone[pos]); 51 } 52 printf("%d\n",cnt); 53 return 0; 54 } 55 //================fuction code====================
T2代码
T3 异象石
描述
Adera是Microsoft应用商店中的一款解谜游戏。
异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图。这张地图上有N个点,有N-1条双向边把它们连通起来。起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一:
1. 地图的某个点上出现了异象石(已经出现的不会再次出现);
2. 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点);
3. 向玩家询问使所有异象石所在的点连通的边集的总长度最小是多少。
请你作为玩家回答这些问题。
输入格式
第一行有一个整数N,表示点的个数。
接下来N-1行每行三个整数x,y,z,表示点x和y之间有一条长度为z的双向边。
第N+1行有一个正整数M。
接下来M行每行是一个事件,事件是以下三种格式之一:
+ x 表示点x上出现了异象石
- x 表示点x上的异象石被摧毁
? 表示询问使当前所有异象石所在的点连通所需的边集的总长度最小是多少。
1 ≤ n, m ≤ 10^5, 1 ≤ x, y ≤ n, x ≠ y, 1 ≤ z ≤ 10^9
输出格式
对于每个 ? 事件,输出一个整数表示答案。
个人认为非常好的一道题。
一棵树,给你一些动态变化的点,要求求出链接这些点的最短道路是多少。
对于无根树,我们经常可以选定一个根节点化为有根树。
以1节点为根,进行dfs,得到每个点的dfs编号。
把有异象石的节点按dfs序从小到大排好序,答案就是该序列中相邻两个数的距离和。
这么说答案可能还是不容易求,那么用这个办法:求出每个点和它的前驱、后继(最小点的前驱是最大点,最大点的后继是最小点)的点的距离,这个距离之和就是答案的两倍。
由于篇幅原因,在此不给出证明。<del>其实我不会证</del>
画图很容易看出。
维护这个序列set可以很容易地完成,求出距离可以用LCA。所有操作均为log(n)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <list> 12 #include <vector> 13 #include <ctime> 14 #include <functional> 15 #define pritnf printf 16 #define scafn scanf 17 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned int Uint; 21 const int INF=0x7ffffff; 22 //==============struct declaration============== 23 struct adj{ 24 int to,dist; 25 adj(int to=0,int dist=0):to(to),dist(dist){} 26 }; 27 //==============var declaration================= 28 const int MAXN=100100; 29 vector <adj> Edge[MAXN]; 30 int depth[MAXN],pa[20][MAXN],n,q,maxd=-1,pre[MAXN],no[MAXN],Index=0; 31 LL dist[20][MAXN],ans=0; 32 set <int> Stone; 33 //==============function declaration============ 34 void dfs(int x); 35 void init(); 36 LL lca(int u,int v); 37 set <int>::iterator L(set <int>::iterator it); 38 set <int>::iterator R(set <int>::iterator it); 39 //==============main code======================= 40 int main() 41 { 42 scanf("%d",&n); 43 For(i,1,n-1){ 44 int s,e,t; 45 scanf("%d%d%d",&s,&e,&t); 46 Edge[s].push_back(adj(e,t)); 47 Edge[e].push_back(adj(s,t)); 48 } 49 memset(pa,-1,sizeof(pa)); 50 memset(dist,0,sizeof(dist));depth[1]=1; 51 dfs(1);init(); 52 scanf("%d",&q); 53 set <int>::iterator it,itl,itr; 54 while (q--){ 55 char cmd;int k; 56 scanf("%c",&cmd); 57 while (cmd!='+'&&cmd!='-'&&cmd!='?') 58 scanf("%c",&cmd); 59 if (cmd=='+'){ 60 scanf("%d",&k); 61 Stone.insert(pre[k]); 62 it=Stone.find(pre[k]); 63 ans+=lca(*L(it),*it); 64 ans+=lca(*R(it),*it); 65 ans-=lca(*R(it),*L(it)); 66 } 67 else if (cmd=='-'){ 68 scanf("%d",&k); 69 it=Stone.find(pre[k]); 70 ans-=lca(*L(it),*it); 71 ans-=lca(*R(it),*it); 72 ans+=lca(*R(it),*L(it)); 73 Stone.erase(it); 74 } 75 else if (cmd=='?') 76 printf("%lld\n",ans/2); 77 } 78 return 0; 79 } 80 //================fuction code==================== 81 void dfs(int x) 82 { 83 pre[x]=++Index; 84 no[Index]=x; 85 int siz=Edge[x].size()-1; 86 For(i,0,siz){ 87 adj &e=Edge[x][i]; 88 if (depth[e.to]==0){ 89 depth[e.to]=depth[x]+1; 90 pa[0][e.to]=x; 91 dist[0][e.to]=e.dist; 92 dfs(e.to); 93 } 94 } 95 maxd=max(maxd,depth[x]); 96 } 97 void init() 98 { 99 for(int i=0;(1<<i)<=maxd;i++) 100 For(x,1,n){ 101 int r=pa[i][x]; 102 if (r<0) 103 pa[i][x]=-1; 104 else{ 105 pa[i+1][x]=pa[i][r]; 106 dist[i+1][x]=dist[i][x]+dist[i][r]; 107 } 108 } 109 } 110 set <int>::iterator L(set <int>::iterator it) 111 { 112 if (it==Stone.begin()) 113 return --Stone.end(); 114 return --it; 115 } 116 set <int>::iterator R(set <int>::iterator it) 117 { 118 if (it==--Stone.end()) 119 return Stone.begin(); 120 return ++it; 121 } 122 LL lca(int u,int v) 123 { 124 LL res=0; 125 u=no[u];v=no[v]; 126 if (depth[u]<depth[v])//保证u在下面 127 u^=v^=u^=v; 128 for(int i=0;(1<<i)<=depth[u]-depth[v];i++) 129 if ((depth[u]-depth[v])&(1<<i)){ 130 res+=dist[i][u]; 131 u=pa[i][u]; 132 } 133 if (u==v) return res; 134 for(int i=18;i>=0;i--) 135 if (pa[i][v]!=pa[i][u]){ 136 res+=dist[i][u]+dist[i][v]; 137 u=pa[i][u];v=pa[i][v]; 138 } 139 return res+dist[0][v]+dist[0][u]; 140 }
T3代码
比赛网址:http://ch.ezoj.tk/contest/CH%20Round%20%2356%20-%20%E5%9B%BD%E5%BA%86%E8%8A%82%E6%AC%A2%E4%B9%90%E8%B5%9B
转载于:https://www.cnblogs.com/Houjikan/p/4011839.html
CH Round #56 - 国庆节欢乐赛解题报告相关推荐
- Codeforces Round #677 (Div. 3)——ABCDE解题报告
Codeforces Round #677 (Div. 3)--ABCDE解题报告 比赛链接:https://codeforces.com/contest/1433 A.Boring Apartmen ...
- Codeforces Round #698 (Div. 2) A-E解题报告与解法证明
Codeforces Round #698 (Div. 2) A-E解题报告与解法证明 题目解法总体概括 A Nezzar and Colorful Balls #include <bits/s ...
- 2014 ACM/ICPC 北京赛区网络赛解题报告汇总
首页 算法竞赛» 信息聚合 ONLINE JUDGE 书刊杂志 BLOG» 新闻故事» 招聘信息» 投稿须知 2014 ACM/ICPC 北京赛区网络赛解题报告汇总 九月 21st, 2014 | P ...
- 20221126测试赛解题报告
20221126测试赛解题报告 1.孤独照片 [USACO21DEC] Lonely Photo B 题目描述 Farmer John 最近购入了 NNN 头新的奶牛(3≤N≤5×1053 \le N ...
- 清澄11.26测试赛解题报告
清澄11.26测试赛解题报告 孤独照片 问题描述 Farmer John 最近购入了 N 头新的奶牛(3≤n≤5*105),每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一 ...
- WHU校赛2019(网络赛) 解题报告(CCNU_你们好强啊我们都是面包手) Apare_xzc
WHU校赛2019(网络赛) 解题报告 CCNU_你们好强啊我们都是面包手(xzc zx lj) 战况: 比赛时3题,排名57,现在5题了 题目链接: WHU校赛2019 <-戳这里 以下题目按 ...
- 湖南师范大学2021年4月1日愚人赛解题报告与标程
湖南师范大学2021年4月1日愚人赛解题报告与标程 A 题目描述 标程 B 题目描述 标程 C 题目描述 标程 D 题目描述 解法 标程 E 题目描述 解法 F 题目描述 解法 标程 G 题目描述 标 ...
- QLU ACM 2018新生赛解题报告
QLU ACM 2018 新生赛解题报告 A [1303]约数个数 题目描述 输入 输出 解析 B [1301]Alice and Bob 题目描述 输入 解析 C [1289] 黑白黑 题目描述 输 ...
- 10.30 NFLS-NOIP模拟赛 解题报告
总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没 ...
- 山东科技大学第二届ACM校赛解题报告
这次校赛的目的,是为了省赛测试各种程序是否有问题. 热身赛的逗比题有点打击我,感觉正式赛应该不会出这种问题.开始的时候直接上了A题,然后大概是第六,前面好多友情队,正式队排名第二. 然后读了读B题,稍 ...
最新文章
- springboot 启动的时候报错 Error creating bean with name 'solrClient'
- restful url 设计规范_RESTful API接口设计规范
- vim java 注释_centOS7 下的vim java补全
- matlab 不同尺度的矩阵存储
- EndNote的PDF Handing功能, 让你的PDF管理井井有条
- openfire SparkWeb 安装配置
- zabbix源码安装实例
- 如何用WebIDE打开并运行CRM Fiori应用 1
- 怎样用计算机演示声音的波形,趣味物理实验 用计算机观察声音的波形
- 小米wifi怎么创建虚拟服务器,小米路由器玩法:一键安装LLMP 建自己的网站
- PTA程序设计基础6 7-1 列表排序、逆序 (10 分)C语言解法
- ArcGIS学习总结(12)——拓扑检查和修正
- 简单使用Java实现微信公众号推送模板消息
- python爬取豆瓣Top250-改进版
- python怎么开发服务器_Python服务器开发(1)
- HTML5UI横向排列,5个实用的UI排版技巧,让你的作品更细致
- OC 技术 获取设备的UDID添加到开发者账号(视频)
- xp升级到win7傻瓜教程_MeGUI教程-软件环境配置(转)
- 计算机不断自动重启,电脑一直自动重启,手把手教你电脑一直自动重启怎么解决...
- Android Studio 实现视频播放暂停功能