Atcoder Beginner Contest 330 题解

AtCoder Beginner Contest 330 题解

A - Counting Passes 签到

void Showball(){
   int n,l;
   cin>>n>>l;
   int cnt=0;
   for(int i=0;i<n;i++){
    int x;
    cin>>x;
    cnt+=(x>=l);
   }
   cout<<cnt<<endl; 
}

B - Minimize Abs 1 思维

void Showball(){
   int n,l,r;
   cin>>n>>l>>r;
   vector<int> a(n);
   for(int i=0;i<n;i++) cin>>a[i];
   for(int i=0;i<n;i++){
    if(a[i]>r) cout<<r<<" ";
    else if(a[i]<l) cout<<l<<" ";
    else cout<<a[i]<<" "; 
   }
}

C - Minimize Abs 2 二分

枚举\(x\),二分\(y\)。更新答案即可。

LL sq[N];
void Showball(){
   for(int i=1;i<N;i++) sq[i]=1LL*i*i;
   LL d;
   cin>>d;
   LL ans=1e18;
   for(LL i=1;i*i<=d;i++){
     LL cur=d-i*i;
    int j=lower_bound(sq,sq+N,cur)-sq;
    if(sq[j]==cur) return cout<<0<<endl,void();
    ans=min(ans,abs(cur-sq[j]));
    ans=min(ans,abs(cur-sq[j-1]));
   }
   cout<<ans<<endl;
}

D - Counting Ls 计数

定义:

\(col[i]\)表示第\(i\)行 '\(o\)' 数量。

\(row[j]\)表示第\(j\)列 '\(o\)' 数量。

那么对于任意一个\((i,j)\)满足\(a[i][j]==\)'\(o\)',对答案的贡献即为\((col[i]-1)\times(row[j]-1)\)

因为不存在和\((i,j)\)同行且同列的情况。所以计算结果不重不漏。

char a[N][N];
int col[N],row[N];
void Showball(){
   int n;
   cin>>n;
   for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        cin>>a[i][j];
        if(a[i][j]=='o'){
            col[i]++;
            row[j]++;
        }
    }
   }

   LL ans=0;
   for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        if(a[i][j]=='o'){
            ans+=(col[i]-1)*(row[j]-1);
        }
    }
   }
   cout<<ans<<endl;
}

E - Mex and Update 思维 诈骗

单调修改,求整体\(mex\)
根据mex的性质,那么范围只可能\([0,n]\)
用数组去统计每个数出现的次数,先将次数为0的全部放进\(set\),那么\(set\)中最小值就是\(mex\)
对于单点修改,我们直接更新次数,并且维护一下\(set\)即可。

void Showball(){
    int n,q;
    cin>>n>>q;
    vector<int> a(n),cnt(n+1);
    set<int> s;
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(a[i]<=n) cnt[a[i]]++;
    } 
    for(int i=0;i<=n;i++) if(!cnt[i]) s.insert(i); 
    while(q--){
        int x,v;
        cin>>x>>v;
        x--;
        if(a[x]<=n){
         if(!--cnt[a[x]]) s.insert(a[x]);
        }
        if(v<=n){
         if(++cnt[v]==1) s.erase(v);
        }
        a[x]=v;
        cout<<*s.begin()<<endl;
    }
}

F - Minimize Bounding Square 二分答案

要求边长的最小值,容易想到二分答案。
考虑\(check\)函数如何去写,那么就需要去求出所有点到变成为\(h\)正方形的最短距离之和。

我们发现横纵坐标相互之间没有影响,所以可以分开进行计算。

我们只知道正方形的边长,却不知道正方形的位置。所以正方形可以进行平移至理想情况。

所以我们发现如果两个端点在正方形的外面,那么移动次数就为\(y_1-y_2-h\)。而两个在里面的情况,移动次数就为\(0\)。所以我们可以对横纵坐标排序。那么每次的移动次数就是\((x[n-i-1]-x[i]-h)\),显然如果小于\(0\),说明都在里面,记为\(0\)即可。

void Showball(){
   int n;
   LL k;
   cin>>n>>k;
   vector<int> x(n),y(n);
   for(int i=0;i<n;i++) cin>>x[i]>>y[i];
   sort(all(x));
   sort(all(y));

   auto check=[&](int h){
     LL cnt=0;
     for(int i=0;i<=n/2;i++){
        cnt+=max(0,x[n-i-1]-x[i]-h);
        cnt+=max(0,y[n-i-1]-y[i]-h);
     }
     return cnt<=k;
   };
   int l=0,r=1e9+1;
   while(l<r){
     int mid=l+r>>1;
     if(check(mid)) r=mid;
     else l=mid+1;
   }
   cout<<l<<endl;
}
posted @ 2024-01-16 12:01  Showball  阅读(6)  评论(0编辑  收藏  举报