AtCoder Beginner Contest 273 A-F题解

rank447,算是不错了。
赛时过到 E ,赛后准备补到 G。

1|0A

n!

1|1Solution

根据题意搜索或递推即可。

1|2Code

int f(int x){ if(x==0)return 1; return x*f(x-1); } int main(){ int n;read(n); cout<<f(n); return 0; }

2|0B

给定一个整数,要求对它每一位分别四舍五入。

2|1Solution

先把要求的那一位后面的全除掉,如果需要进位,就把得到的数加 1,再还原回去。

2|2Code

手写快速幂。

int x,k; read(x);read(k); for(int i=1;i<=k;i++){ int k=x/Pow(10,i-1)%10;//取出那一位,判断要不要进位 x/=Pow(10,i);x+=(k>4); x*=Pow(10,i); } cout<<x;

3|0C

求出对于每个 k[0,k1],有多少个数满足恰好有 k 数大于它。

3|1Solution

先离散化后记为 ti,设值域为 len,求出每个值是否对应有数,并求前缀和,记为 si,考虑每个数对答案的贡献,比它大的数的个数就是 slensti,将答案数组加上即可,具体见代码。

3|2Code

#include<bits/stdc++.h> #define int long long #define fi first #define se second using namespace std; using ll=long long; using pii=pair<int,int>; using pll=pair<ll,ll>; using ull=unsigned long long; inline void read(int &x){ char ch=getchar(); int r=0,w=1; while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar(); while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar(); x=r*w; } const int N=2e5+7; int a[N],b[N],t[N],s[N],ans[N],n,len; void init(){ for(int i=1;i<=n;i++)b[i]=a[i]; sort(b+1,b+n+1); len=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) t[i]=lower_bound(b+1,b+len+1,a[i])-b,s[t[i]]=1; for(int i=1;i<=len;i++)s[i]+=s[i-1]; } main(){ read(n); for(int i=1;i<=n;i++)read(a[i]); init(); for(int i=1;i<=n;i++) ans[s[len]-s[t[i]]]++; for(int i=0;i<n;i++)printf("%lld\n",ans[i]); return 0; }

4|0D

L R U D四种操作,每次询问操作 li 次,遇到墙则停下,问会到达哪个位置。

4|1Solution

很明显需要对于每一行列记录墙的位置,并且需要排好序方便二分查找,用 map 套 set 即可。

每次二分找到当前方向离当前位置最近的墙,看走 li 步会不会被拦下来。

因为不能走出范围,这就很恶心,为了避免大量的特判,我们可以对于行,将 0m+1 设为墙,对于列,将 0n+1 设为墙,这样代码会好写很多。

4|2Code

#include<bits/stdc++.h> using namespace std; #define int long long void read(int &x) { char ch=getchar(); int r=0,w=1; while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar(); while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar(); x=r*w; } map<int,set<int> >f1; map<int,set<int> >f2; signed main() { int n,m,sx,sy,t,q; read(n),read(m),read(sx),read(sy); read(t); while(t--) { int x,y; read(x),read(y); f1[x].insert(y); f2[y].insert(x); } read(q); while(q--) { f1[sx].insert(0);f1[sx].insert(m+1); f2[sy].insert(0);f2[sy].insert(n+1);//将边界设为墙 char op; int d,tx,ty; cin>>op;read(d); if(op=='L') { ty=*--f1[sx].lower_bound(sy); if(sy-ty-1>=d)sy-=d; else sy=ty+1; } if(op=='R') { ty=*f1[sx].upper_bound(sy); if(ty-sy-1>=d)sy+=d; else sy=ty-1; } if(op=='U') { tx=*--f2[sy].lower_bound(sx); if(sx-tx-1>=d)sx-=d; else sx=tx+1; } if(op=='D') { tx=*f2[sy].upper_bound(sx); if(tx-sx-1>=d)sx+=d; else sx=tx-1; } printf("%lld %lld\n",sx,sy); } return 0; }

5|0E

题面很长,就不放简要题面了。

5|1Solution

看起来很难,不过是个诈骗题,你直接用双向指针暴力模拟,然后开几个数组去存时间线就可以了。

5|2Code

#include<bits/stdc++.h> #define int long long using namespace std; inline void read(int &x){ char ch=getchar(); int r=0,w=1; while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar(); while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar(); x=r*w; } const int N=1e6+7; int fa[N],pre[N],f[N],cnt; map<int,int>mp; main() { int q; read(q); f[0]=-1; for(int i=1;i<=q;i++) { string s;int x; cin>>s; if(s[0]=='A'){ read(x); fa[i]=++cnt; f[cnt]=x;pre[cnt]=fa[i-1]; } if(s[0]=='D')fa[i]=pre[fa[i-1]]; if(s[0]=='S'){ read(x); fa[i]=fa[i-1];mp[x]=i; } if(s[0]=='L'){ read(x); fa[i]=fa[mp[x]]; } printf("%lld\n",f[fa[i]]); } return 0; }

6|0F

平面上有墙和锤子,一个锤子对应只能敲掉一面墙,最开始在原点,给定终点,问最小步数。

6|1Solution

赛时降智,一个简单 DP 应该要过的,客观原因是因为改 D 改了很久。

首先坐标较大可以离散化掉,设 f(i,j,0/1) 表示在区间 [i,j] 的左端或右端的最小答案,然后就写完了,暴力转移即可。在区间扩展的时候,如果扩展到的是墙,要判断当前区间是否包含敲掉那面墙的锤子。

6|2Code

代码贺的。

#include<bits/stdc++.h> #define int long long #define fi first #define se second using namespace std; using ll=long long; using pii=pair<int,int>; using pll=pair<ll,ll>; using ull=unsigned long long; inline void read(int &x){ char ch=getchar(); int r=0,w=1; while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar(); while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar(); x=r*w; } const int N=3e3+7; int n,T,s[N],t[N],x[N],m,nd[N]; int f[N][N][2]; main(){ read(n);read(T); for(int i=1;i<=n;i++)read(t[i]),x[++m]=t[i]; for(int i=1;i<=n;i++)read(s[i]),x[++m]=s[i]; x[++m]=0,x[++m]=T; sort(x+1,x+m+1);m=unique(x+1,x+m+1)-x-1; for(int i=1;i<=n;i++)s[i]=lower_bound(x+1,x+m+1,s[i])-x; for(int i=1;i<=n;i++)t[i]=lower_bound(x+1,x+m+1,t[i])-x,nd[t[i]]=i; int S=lower_bound(x+1,x+m+1,0)-x; T=lower_bound(x+1,x+m+1,T)-x; memset(f,63,sizeof f); f[S][S][0]=f[S][S][1]=0; for(int len=1;len<m;len++) for(int l=1;l<=m;l++){ int r=l+len-1; if(l>1){ int p=nd[l-1]; if(!p||(p&&l<=s[p]&&s[p]<=r)){ f[l-1][r][0]=min(f[l-1][r][0],f[l][r][0]+x[l]-x[l-1]); f[l-1][r][0]=min(f[l-1][r][0],f[l][r][1]+x[r]-x[l-1]); } } if(r<m){ int p=nd[r+1]; if(!p||(p&&l<=s[p]&&s[p]<=r)){ f[l][r+1][1]=min(f[l][r+1][1],f[l][r][0]+x[r+1]-x[l]); f[l][r+1][1]=min(f[l][r+1][1],f[l][r][1]+x[r+1]-x[r]); } } } int res=1e18; for(int i=1;i<=T;i++) for(int j=T;j<=m;j++) res=min({res,f[i][j][0],f[i][j][1]}); if(res==(int)1e18)puts("-1"); else printf("%lld\n",res); return 0; }

__EOF__

本文作者JMartin
本文链接https://www.cnblogs.com/LAK666/p/16795179.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Epoch_L  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示