AtCoder Beginner Contest 273 A-F题解

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

A

\(n!\)

Solution

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

Code

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;
}

B

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

Solution

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

Code

手写快速幂。

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;

C

求出对于每个 \(k\in[0,k-1]\),有多少个数满足恰好有 \(k\) 数大于它。

Solution

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

Code

#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;
}

D

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

Solution

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

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

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

Code

#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;
}

E

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

Solution

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

Code

#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;
}

F

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

Solution

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

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

Code

代码贺的。

#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;
}
posted @ 2022-10-15 22:20  Epoch_L  阅读(97)  评论(0)    收藏  举报