华东交通大学2022年ACM“双基“程序设计竞赛
admin
2024-02-03 05:47:02

Fly

1.铁路

题意:
n个点,m条路将其连起来。
q次询问,
opt=1时输出A,B两点的最短距离;
opt=2时在A,B之间修建一条花费时间C的铁路。

思路:
先无向边建图,
注意:可能有重边和自环,
因此,如果是自环,d应该取0;
如果有重边,应取其中w最小的。
首先做一次Floyd算法,先求出任意两点之间的最短距离。
然后对于每次询问,
opt=1直接输出。
opt=2时,如果f[a][b]>c,更新f[a][b]和f[b][a],
并做一次Floyd算法。

代码:

include 
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 210;
int n,m,q,f[N][N],opt,a,b,c;void floyd(){for(int k=1;k<=n;k++){//k为中间点 for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){f[i][j]=min(f[i][j],f[i][k]+f[k][j]);}}}
}int main(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==j) f[i][j]=0;else f[i][j]=INF;}}for(int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);f[x][y]=f[y][x]=min(f[x][y],z);}floyd();//首先做一遍floyd while(q--){scanf("%d%d%d",&opt,&a,&b);if(opt==1){//直接输出 printf("%d\n",f[a][b]);}else{scanf("%d",&c);if(f[a][b]>c){//如果大于//更新并做一遍floyd f[a][b]=f[b][a]=min(f[a][b],c);floyd();}}}return 0;
}

2.n层妖塔

题意:
m个挑战者,n层楼。当挑战者的战力>第i层楼的守护者的战力时,
花费1个单位时间将其击败,击败第i层之后可以前往第i+1层,
当战胜第n层的守护者后,视为挑战成功。
当挑战者的战力<=第i层楼的守护者的战力时,可以花费相应时间修炼获得战力,
当获得a[i]+1的战力之后,就可以打败这个守护者了。
计算每一位挑战者挑战成功所需要花费的最短时间。

思路:
先预处理出每一层至少需要多少战力才能毫无阻碍地挑战成功。
因为最终要战胜第n层的守护者之后,才视为挑战成功。
设f[i]表示第i层至少需要的战力,
那么由于第n层是终结层,因此f[n]=a[n]+1;
然后开始从第n层递推到第1层。
对于每一层:要么取a[i]+1,
要么因为每次前进,所以后一层会对前一层有限制,
因此要么就是f[i+1]-1,-1是除去打败这一层所需的时间。
f[i]=max(a[i]+1,f[i+1]-1);

代码:

#include 
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n,m,a[N],f[N];int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);f[n]=a[n]+1;for(int i=n;i>=1;i--){f[i]=max(a[i]+1,f[i+1]-1); } while(m--){int x,y;scanf("%d%d",&x,&y);if(x>=f[y]) printf("%d\n",n-y+1);//仅为每次打败所需时间 else printf("%d\n",n-y+1+(f[y]-x));//还要加上修炼的时间 }return 0;
}

3.火车摆放

题意:
n个火车,对于任意i属于[2,n],第i号火车只能连在第i-1号火车的后面。
m次操作,
1.(1,x):如果第x1号火车存在,则接在第x1号火车后面,
如果第x+1号火车也存在,则将第x+1号火车接在第x号火车后面),
如果第x号火车已经被摆放了,则忽略该操作。
2.(2,x)表示将第x号火车拆下来,如果第x号火车已经被拆掉了,则忽略该操作。
3.(3,x)询问以第x号火车为车头的连续列车长度是多少。

思路:
本来想的是利用set,因为set具有自动去重并排序的功能。
1操作就将x加入集合,
2操作就将x从集合中删除,
3操作就在集合中找x的最长连续长度。
但是这样第3个操作会遍历很久,时间复杂度很高。
因此可以逆向思维,
先将1-n加入set集合,
opt=1,删除x;
opt=2,添加x;
opt=3,再进行计算。
因为此时s中存放的是被拆除的火车,即断点。
首先特判,如果这个火车已经被拆除,则输出0;
否则,
当查询以x号火车为车头的连续列车长度时,
只需要去set集合中找到>=x的第一个元素的火车(亦即位置),
如果 相减<0,表示后面一串都行;
否则,输出输出这个 位置-这个火车的位置。
这样的话3操作可以利用STL的lower_bound找到>=x的第一个数,
直接计算最长连续长度。

set小知识

(1)set::lower_bound()是C++
STL中的内置函数,该函数返回指向容器中元素的迭代器,该迭代器等效于在参数中传递的k。如果set容器中不存在k,则该函数返回一个迭代器,该迭代器指向刚好大于k的下一个元素。如果传递给参数的键超过了容器中的最大值,则返回的迭代器将指向设置容器中的最后一个元素。
(2)//删除 set 容器中值为 val 的元素 size_type erase (const value_type& val);
//删除 position 迭代器指向的元素 iterator erase (const_iterator position); //删除
[first,last) 区间内的所有元素 iterator erase (const_iterator first,
const_iterator last);

代码:

#include 
using namespace std;
int n,m,opt,x;
set s;
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) s.insert(i);while(m--){scanf("%d%d",&opt,&x);if(opt==1) s.erase(x);else if(opt==2) s.insert(x);else{if(*s.lower_bound(x)-x<0) printf("%d\n",n-x+1);else printf("%d\n",*s.lower_bound(x)-x);}}return 0;
} 

相关内容

热门资讯

国家能源局:11月全国完成电力... 12月25日,据国家能源局披露,2025年11月,全国完成电力市场交易电量5484亿千瓦时,同比增长...
新疆的冬天亚克西丨从雪场滑到大... 石榴云/新疆日报讯(记者 王晶晶报道)12月23日18时许,乌鲁木齐县板房沟镇八家户村全季草莓采摘基...
国泰上证5年期国债ETF(51... 数据显示,12月24日,国泰上证5年期国债ETF(511010)获净申购1831.33万元,位居当日...
方直科技涨2.02%,成交额8... 12月25日,方直科技盘中上涨2.02%,截至10:15,报16.63元/股,成交8139.06万元...
越剑智能2025年12月25日... 2025年12月25日,越剑智能(sh603095)触及涨停,涨停价15.96元,涨幅9.99%,总...