• Codeforces Round #639 (Div. 2)【ABCD】(题解)


    涵盖知识点:思维、图论

    比赛链接:传送门

    A - Puzzle Pieces

    题意: 给出三面凸一面凹的无限块拼图问是否能拼出n行m列的图形
    题解: 只能一行或者一列或者两行两列。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
        int t;
        cin>>t;
        while (t--){
            int n,m;
            cin>>n>>m;
            if(n==1||m==1||(n==2&&m==2))puts("YES");
            else puts("NO");
        }
        return 0;
    }
    

    B - Card Constructions

    题意: 卡片搭塔,优先搭最高的,剩下的可以接着搭,问最后层数总和。
    题解: 可以算出层数(n)和卡片数(cnt)的关系是(cnt=frac{n^2+n}{2} imes 3-n)。然后从大到小扫一遍即可。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll calc(ll n){
        return (n*(n+1))/2*3-n;
    }
    int main(){
        int t;
        cin>>t;
        while (t--){
            ll n,ans=0;
            cin>>n;
            for(int i=26000;i>=1;i--){
                while(n>=calc(i)){
                    n-=calc(i);
                    ans++;
                }
            }
            cout<<ans<<"
    ";
        }
        return 0;
    }
    

    C - Hilbert's Hotel

    题意: 将第(k)个房间的人重新安排到第(k+a_{kmod n})个房间。问最后是否每个人都在不同的房间。(k)为任意整数。
    题解: 仅考虑(k)([0,n-1])的范围即可。因为安排到新房间就相当于是平移了一定的位置,如果在这一个区间内不会重复那么后一个区间内也会因为互相交换导致满足条件。(有点奇怪的证明,差不多意思到了就好)
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+10;
    int a[maxn];
    map<int,int> mp;
    int main(){
        int t;
        cin>>t;
        while (t--){
            mp.clear();
            int n;
            cin>>n;
            for(int i=0;i<n;i++)cin>>a[i],a[i]=(a[i]%n+n)%n;
            bool check=true;
            for(int i=0;i<n;i++){
                int nr=(i+a[i])%n;
                if(mp[nr]!=0){
                    check=false;
                    break;
                }
                mp[nr]++;
            }
            puts(check?"YES":"NO");
        }
        return 0;
    }
    

    D - Monopole Magnets

    题意: 如果北磁极和南磁极在同一列或者同一行,那么北磁极将会向南磁极的方向移动一个单元格。现在给定一张图,保证白格一定不会有北磁极经过,黑格一定会有北磁极经过。又要求每行每列都必须至少有一个南磁极。求最少安排多少个北磁极可以达成要求。
    题解: 首先判断不可能完成要求的情况。

    • 两个黑格之间存在若干个白格。
    • 存在全白行但不存在全白列
    • 存在全白列但不存在全白行
      第一种情况会导致一旦经过某一个黑格,一定会因为该行存在一个南磁极而经过北磁极
      后两种会因为无法在该行或者该列的某一个位置安放南磁极而不满足条件。
      其余情况判断一下全黑的连通块就可以了。黑色部分全部填上南磁极然后每个连通块随便放一个北磁极即可。
      Accept Code:
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    char mp[maxn][maxn];
    int n,m;
    int vis[maxn][maxn];
    int dx[4]={1,0,-1,0};
    int dy[4]={0,1,0,-1};
    typedef pair<int,int> pii;
    int gx[maxn],gy[maxn];
    void bfs(int x,int y){
        queue<pii> q;
        while(!q.empty())q.pop();
        q.push({x,y});
        while(!q.empty()){
            int ox=q.front().first,oy=q.front().second;
            q.pop();
            for(int i=0;i<4;i++){
                int nx=ox+dx[i],ny=oy+dy[i];
                if(nx<1||nx>n||ny<1||ny>m)continue;
                if((mp[nx][ny]=='#')&&(!vis[nx][ny])){
                    vis[nx][ny]=1;
                    q.push({nx,ny});
                    //printf("%d %d
    ",nx,ny);
                }
            }
        }
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]=='#'){
                    if(gx[i]&&(j-gx[i])>1){
                        puts("-1");
                        return 0;
                    }
                    if(gy[j]&&(i-gy[j])>1){
                        puts("-1");
                        return 0;
                    }
                    gx[i]=j;
                    gy[j]=i;
                }
            }
        }
        int wx=1,wy=1;
        for(int i=1;i<=n;i++){
            if(gx[i]==0){
                wx=0;
                break;
            }
        }
        for(int j=1;j<=m;j++){
            if(gy[j]==0){
                wy=0;
                break;
            }
        }
        if(wx^wy){
            puts("-1");
            return 0;
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if((mp[i][j]=='#')&&(!vis[i][j])){
                    //cout<<i<<" "<<j<<"
    ";
                    vis[i][j]=1;
                    bfs(i,j);
                    ans++;
                }
            }
        }
        cout<<ans<<"
    ";
        return 0;
    }
    
  • 相关阅读:
    最小生成树
    图论最短路径例题
    广搜例题
    这些搜索套路好深。。。
    高斯消元part2
    高斯消元与行列式求值 part1
    2020/4/24
    实时的眼部追踪
    2020/4/23
    2020/4/22
  • 原文地址:https://www.cnblogs.com/charles1999/p/12840428.html
Copyright © 2020-2023  润新知