AtCoder Beginner Contest 254 题解

只有 ABCDEFH 的题解。

A

模拟。

Code
void mian(){
  int n;scanf("%d",&n);
  printf("%02d\n",n%100);
}

B

模拟。

Code
const int N=30;
 
int n;
ll a[N+10][N+10];
 
void mian(){
  scanf("%d",&n);
  a[0][0]=1;
  for(int i=1;i<n;i++){
    a[i][0]=1;
    for(int j=1;j<n;j++)
      a[i][j]=a[i-1][j-1]+a[i-1][j];
  }
  for(int i=0;i<n;i++)
    for(int j=0;j<=i;j++)
      printf("%lld%c",a[i][j]," \n"[j==i]);
}

C

把整个序列分成若干组:

  • \([a_1,a_{1+k},a_{1+2k},\cdots]\)
  • \([a_2,a_{2+k},a_{2+2k},\cdots]\)
  • \(\cdots\)

那么,每组内部的数可以随便换,组与组之间互不影响。把每组数排序后,再来看整个序列是否有序即可。

Code
const int N=2e5;
 
int n,k,a[N+10],b[N+10];
bool vis[N+10];
 
void mian(){
  scanf("%d%d",&n,&k);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i);
  for(int i=1;i<=n-k;i++){
    if(vis[i])continue;
    int cnt=0;
    for(int j=i;j<=n;j+=k)
      b[++cnt]=a[j],vis[j]=1;
    std::sort(b+1,b+cnt+1);
    for(int j=i,kk=1;j<=n&&kk<=cnt;j+=k,kk++)
      a[j]=b[kk];
  }
  if(std::is_sorted(a+1,a+n+1))puts("Yes");
  else puts("No");
}

D

做法貌似很多,这里说一下我的。

先枚举 \(i\),然后看有多少个 \(j\) 满足要求。

\(i\) 中所有 \(p^2\) 的因子刨掉,设得到的数是 \(i'\),那么有 \(\sqrt{\frac n{i'}}\)\(j\)

枚举 \(p\) 时枚举到 \(\sqrt n\) 就行了,因为再大的数没有意义。

Code
const int N=2e5;
const int M=450;
 
int n;
int prm[M+10],notPrm[M+10],totp;
 
void init(){
  notPrm[1]=1;
  for(int i=2;i<=M;i++){
    if(!notPrm[i])prm[++totp]=i;
    for(int j=1;j<=totp&&i*prm[j]<=M;j++){
      notPrm[i*prm[j]]=1;
      if(!i%prm[j])break;
    }
  }
}
 
int get(int x){
  for(int i=1;i<=totp;i++){
    int y=prm[i];
    while(x%(y*y)==0)x/=(y*y);
  }
  return x;
}
 
void mian(){
  scanf("%d",&n);
  ll ans=0;
  for(int i=1;i<=n;i++){
    int x=get(i);
    ans+=int(std::sqrt(n/x));
  }
  printf("%lld\n",ans);
}

E

直接用 std::queue 之类的暴力就行了。

比赛时我想了一个又奇怪又麻烦的做法,这里就不放出来了。

F

\(\gcd\) 有一个最基本的性质:\(\gcd(a,b)=\gcd(a,a-b)\)

于是要求的就变成了(以 \(h_1=1,h_2=n,w_1=1,w_2=n\) 为例):

\[\gcd(a_1+b_1,a_2-a_1,\cdots,a_n-a_{n-1},b_2-b_1,\cdots,b_n-b_{n-1}) \]

用 ST 表维护 \(a,b\) 差分的 \(\gcd\) 即可。

Code
const int N=2e5;
const int LOGN=20;
 
int n,q,a[N+10],b[N+10],c[N+10],d[N+10];
 
struct ST{
  int lg[N+10],gcd[N+10][LOGN+5];
  void init(int n,int *a){
    lg[0]=-1;
    for(int i=1;i<=n;i++)
      gcd[i][0]=a[i],lg[i]=lg[i>>1]+1;
    for(int j=1;j<=LOGN;j++)
      for(int i=1;i<=n-(1<<j)+1;i++)
        gcd[i][j]=std::__gcd(gcd[i][j-1],gcd[i+(1<<(j-1))][j-1]);
  }
  int query(int l,int r){
    int k=lg[r-l+1];
    return std::__gcd(gcd[l][k],gcd[r-(1<<k)+1][k]);
  }
}A,B;
 
void mian(){
  scanf("%d%d",&n,&q);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i);
  for(int i=1;i<=n;i++)
    scanf("%d",b+i);
  for(int i=1;i<=n;i++){
    c[i]=std::abs(a[i]-a[i-1]);
    d[i]=std::abs(b[i]-b[i-1]);
  }
  A.init(n,c);
  B.init(n,d);
  while(q--){
    int x1,y1,x2,y2;
    scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
    if(x1==x2&&y1==y2)printf("%d\n",a[x1]+b[y1]);
    else if(x1==x2)printf("%d\n",std::__gcd(a[x1]+b[y1],B.query(y1+1,y2)));
    else if(y1==y2)printf("%d\n",std::__gcd(a[x1]+b[y1],A.query(x1+1,x2)));
    else printf("%d\n",std::__gcd(a[x1]+b[y1],std::__gcd(A.query(x1+1,x2),B.query(y1+1,y2))));
  }
}

H

首先有一个巧妙的转化:给 \(a\) 中某个数 \(\times 2\) 相当于给 \(b\) 中某个偶数 \(\div 2\)

于是可以做一个贪心:把 \(a,b\) 的数插进大根堆里,每次从两个堆里分别取出堆顶 \(x,y\)。如果 \(x=y\),则他俩就直接匹配上了;如果 \(x>y\),则只能将 \(x\gets\left\lfloor\frac x2\right\rfloor\)(前提是 \(x\ne 0\));如果 \(x<y\),则只能将 \(y\gets\left\lfloor\frac y2\right\rfloor\)(前提是 \(y\ne 0,2\mid y\))。

Code
int n;
std::priority_queue<int> a,b;
 
void mian(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    int x;scanf("%d",&x);
    a.push(x);
  }
  for(int i=1;i<=n;i++){
    int x;scanf("%d",&x);
    b.push(x);
  }
  int ans=0;
  while(!(a.empty()&&b.empty())){
    int x=a.top();
    int y=b.top();
    if(x==y){a.pop();b.pop();continue;}
    if(x>y){
      if(x==0)return puts("-1"),void();
      a.pop();
      a.push(x/2);
      ans++;
    }else{
      if(y==0||(y&1))return puts("-1"),void();
      b.pop();
      b.push(y/2);
      ans++;
    }
  }
  printf("%d\n",ans);
}
posted @ 2022-06-09 16:02  registerGen  阅读(132)  评论(0)    收藏  举报