AtCoder Beginner Contest 273(D-F)
D - LRUD Instructions
题意:给一个棋盘,然后给出N个障碍,然后给出Q次移动,给出移动的方向和移动的距离,如果移动的过程中遇到墙或者障碍,就停止,问每次移动之后停下来的位置。
题解:数据是1e9很大,所以肯定不能遍历,但我们可以看到,实际上会出现的障碍只有2e5个,所以我们可以离散化一下,把数据缩小,然后每次二分查找有没有障碍即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=2e5+5; const ll inf=1e18; const ll mod=998244353; ll n,m; vector<ll> p[N]; vector<ll> q[N]; unordered_map<ll,ll> l,r; ll cnt1,cnt2; signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); ll bx,by; cin>>n>>m>>bx>>by; ll t;cin>>t; while(t--){ ll x,y;cin>>x>>y; if(!l[x]) l[x]=++cnt1;//类似于离散化的操作 if(!r[y]) r[y]=++cnt2; p[l[x]].push_back(y); q[r[y]].push_back(x); } cin>>t; for(ll i=1;i<=cnt1;i++){p[i].push_back(0);p[i].push_back(m+1); sort(p[i].begin(),p[i].end());} for(ll i=1;i<=cnt2;i++){q[i].push_back(0);q[i].push_back(n+1); sort(q[i].begin(),q[i].end());} while(t--){ char s;ll x;cin>>s>>x; if(s=='L'){ if(!p[l[bx]].size()){ by=max(1ll,by-x); } else{ ll pt=*(lower_bound(p[l[bx]].begin(),p[l[bx]].end(),by)-1); by=max(pt+1,by-x); } } else if(s=='R'){ if(!p[l[bx]].size()){ by=min(m,by+x); } else { ll pt=*(lower_bound(p[l[bx]].begin(),p[l[bx]].end(),by));//找到第一个比它大的数 by=min(pt-1,by+x); } } else if(s=='U'){ if(!q[r[by]].size()){ bx=max(1ll,bx-x); } else { ll pt=*(lower_bound(q[r[by]].begin(),q[r[by]].end(),bx)-1);//找到第一个比它小的 bx=max(pt+1,bx-x); } } else { if(!q[r[by]].size()){ bx=min(n,bx+x); } else{ ll pt=*(lower_bound(q[r[by]].begin(),q[r[by]].end(),bx)); bx=min(pt-1,bx+x); } } cout<<bx<<" "<<by<<endl; } }
E - Notebook
题意:四种操作
- add:在序列尾加x
- delete:删除序列最后一个数
- save:将当前的序列保存到第x页
- load:用第x页的序列替换当前的序列
问每次操作结束之后当前序列的最后一个数字是多少,如果没有数字则输出" -1 "。
题解:放在树上操作,利用不同的枝来存储不同的序列。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=5e5+5; const ll inf=1e18; const ll mod=998244353; vector<ll> ans; vector<ll> res; struct ss{ ll w,fa; ss(ll x,ll y){ w=x;fa=y; } }; unordered_map<ll,ll> mp; vector<ss> q; ll cnt; signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); ll n;cin>>n; q.push_back(ss(-1,0)); ll now=0; while(n--){ string s;cin>>s; ll x; if(s!="DELETE") cin>>x; if(s=="ADD"){ q.push_back(ss(x,now)); now=(ll)(q.size()-1); } else if(s=="DELETE"){ now=q[now].fa; } else if(s=="SAVE"){//将当前的节点存储 mp[x]=now; } else now=mp[x];//直接跳转到之前存储的节点 cout<<q[now].w<<" "; } }
F - Hammer 2
题意:给出两个数组,第一个数组表示墙的位置,第二个数组表示锤子的位置,对应的墙需要对应的锤子敲开,开始在0的位置,每次然后最后要到达一个点,问能否到达,不能到达输出-1,能到达输出需要走的最短路程。
题解:dp,可以把问题抽象化为,开始有2*n+2个点.其中2*n是墙的位置和锤子的位置,然后还有起点0和终点m的位置,然后我们每次都选择一个位置去,我们可以再把这些点排序去重离散化,最后得到的一个序列,找到其中0对应的位置,每次都选择一个位置去,然后利用一个l,一个r表示到达的最左边和最右边,用dp[l][r][x]表示最左边到达l,最右边到达r,然后x两个取值(0:上一次移动的方向是向左,也就是当前自身的位置在l ——— 1:上一次移动的方向是向右,也就是当前自身的位置在r),dp[l][r][x]就是这种状态下的满足条件的最小路程。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e3+5; const ll inf=1e18; ll dp[N][N][2]; ll cnt; ll a[N],b[N],q[N]; ll vis[N]; signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); ll n,m;cin>>n>>m; for(ll i=1;i<=n;i++) cin>>a[i],q[++cnt]=a[i]; for(ll i=1;i<=n;i++) cin>>b[i],q[++cnt]=b[i]; q[++cnt]=0,q[++cnt]=m;//将所有点放到q数组中 sort(q+1,q+1+cnt);//排序 cnt=unique(q+1,q+1+cnt)-q-1;//去重 for(ll i=1;i<=n;i++) b[i]=lower_bound(q+1,q+1+cnt,b[i])-q;//离散化 for(ll i=1;i<=n;i++) a[i]=lower_bound(q+1,q+1+cnt,a[i])-q,vis[a[i]]=b[i];//注意这句话和上一句话的顺序,要先给锤子赋值,再给墙赋值,因为这里要用一个vis数字去记录每一个墙对应的锤子的位置 ll beg=lower_bound(q+1,q+1+cnt,0)-q;//找到开始0的位置 memset(dp,0x3f,sizeof(dp)); dp[beg][beg][0]=dp[beg][beg][1]=0; for(ll len=1;len<=cnt;len++)//遍历区间的长度 for(ll l=1;l<=cnt;l++){ ll r=l+len-1;//右端点 if(l>1){//要向左移动所以l>1 ll pt=vis[l-1];//判断左边的位置是不是墙,是墙的话钥匙在不在[l,r]内 if(!pt||(pt&&pt>=l&&pt<=r)){ dp[l-1][r][0]=min(dp[l-1][r][0],dp[l][r][0]+q[l]-q[l-1]); dp[l-1][r][0]=min(dp[l-1][r][0],dp[l][r][1]+q[r]-q[l-1]); } } if(r<cnt){ ll pt=vis[r+1];; if(!pt||(pt&&pt>=l&&pt<=r)){ dp[l][r+1][1]=min(dp[l][r+1][1],dp[l][r][0]+q[r+1]-q[l]); dp[l][r+1][1]=min(dp[l][r+1][1],dp[l][r][1]+q[r+1]-q[r]); } } } ll ans=inf; m=lower_bound(q+1,q+1+cnt,m)-q;//找到终点 for(ll i=1;i<=m;i++) for(ll j=m;j<=cnt;j++){//找到最小值 ans=min(min(ans,dp[i][j][0]),dp[i][j][1]); } if(ans==1e18) cout<<"-1"<<endl; else cout<<ans; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现