返回顶部

Codeforces Round #648 (Div. 2)【ABCDEF】(题解)

涵盖知识点:思维

比赛链接:传送门

A - Matrix Game

题意: 两人博弈,依次在\(01\)矩阵中将某个\(0\)变为\(1\),且该位置原本的行列中都不存在\(1\)
题解: 记录行列中没有\(1\)的数量,取最小值判断奇偶性即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
int a[110][110];
bool visr[110],visc[110];
int main(){
    int t;cin>>t;
    while(t--){
        memset(visr,0,sizeof visr);
        memset(visc,0,sizeof visc);
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>a[i][j];
                if(a[i][j]==1){
                    visr[i]=visc[j]=1;
                }
            }
        }
        int cr=0,cc=0;
        for(int i=1;i<=n;i++)if(visr[i]==0)cr++;
        for(int i=1;i<=m;i++)if(visc[i]==0)cc++;
        if(min(cr,cc)&1)puts("Ashish");
        else puts("Vivek");
    }
    return 0;
}

B - Trouble Sort

题意: 数组中所有数字由\(0,1\)两种类型,每次可以交换数组中两个类型不同的数字,问若干次操作后是否可以使得数组从小到大排序。
题解: 注意到只要不是所有类型都相同,我们一定可以通过多次交换使得数组最终完成排序。所以只要判断是不是所有数字的类型都相同且初始状态下并非排序完成的结果即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=550;
int a[maxn],b[maxn];
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        sort(b,b+n);
        if(b[0]==b[n-1]&&!is_sorted(a,a+n))puts("No");
        else puts("Yes");
    }
    return 0;
}

C - Rotation Matching

题意: 给定两个\(1到n\)排列数组\(a,b\)。问怎么循环位移可以使得匹配的数量尽可能的多。求匹配数量。
题解: 记录\(b\)中每个数字位移到\(a\)中对应匹配位置所需的位移量。对所有的位移量所被记录的次数求一个最大值即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],b[maxn],idx[maxn];
map<int,int> cnt;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],idx[a[i]]=i;
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++){
        int sub=idx[b[i]]-i;
        if(sub<0)sub+=n;
        cnt[sub]++;
    }
    int ans=0;
    for(auto i:cnt)ans=max(ans,i.second);
    cout<<ans<<"\n";
    return 0;
}

D - Solve The Maze

题意: 地图上有空地,墙,好人,坏人四种类型。规定右下角为出口。问能否再安排一些墙使得好人都能到出口,且坏人都不能到达出口。
题解: 我们只要将坏人的四周围起来。具体实现的时候,只要坏人的四周不是坏人,那么就在这个位置安排一个墙。最后从出口开始反向深搜检查每一个好人能否到达出口。注意坏人的四周如果是好人,我们将其直接覆盖为墙。由于坏人四周存在好人,那么坏人一定能够到达出口。这不会影响我们最后得到的结果。
Accept Code:

#include <bits/stdc++.h>
using namespace std;

const int maxn=110;
char mp[maxn][maxn];
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};
bool vis[maxn][maxn];
int n,m;
int dfs(int x,int y){
    int res=0;
    if(x<0||x>=n||y<0||y>=m)return 0;
    if(vis[x][y]||mp[x][y]=='#')return 0;
    vis[x][y]=1;
    if(mp[x][y]=='G')res++;
    for(int i=0;i<4;i++)res+=dfs(x+dx[i],y+dy[i]);
    return res;
}
int main(){
    int t;cin>>t;
    while(t--){
        memset(vis,0,sizeof vis);
        cin>>n>>m;
        int sum=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cin>>mp[i][j];
                if(mp[i][j]=='G')sum++;
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                //if(mp[i][j]=='G')sum++;
                if(mp[i][j]=='B'){
                    if(i!=0&&mp[i-1][j]!='B')mp[i-1][j]='#';
                    if(i!=n-1&&mp[i+1][j]!='B')mp[i+1][j]='#';
                    if(j!=0&&mp[i][j-1]!='B')mp[i][j-1]='#';
                    if(j!=m-1&&mp[i][j+1]!='B')mp[i][j+1]='#';
                }
            }
        }
        if(sum==dfs(n-1,m-1))puts("Yes");
        else puts("No");
    }
    return 0;
}

E - Maximum Subsequence Value

题意:\(n\)个数字中选取\(k\)个,要求最大化这\(k\)个数字构成集合的价值。定义集合的价值为在二进制下,若第\(i\)位至少存在\(\max(1,k-2)\)\(1\),那么对价值产生\(2^i\)的贡献。
题解: 分析可得\(k=3\)时最优。首先,若\(k=1,2\),每一位同样需要存在\(1\)\(1\),那么相同情况下增加一个数字只会使得值更大。若\(k\ge 4\),在\(k=3\)时恰好满足的条件下多出来的数字的每一位必须要满足一定的条件,否则值只会更小。所以我们可以暴力枚举每三项的或值取最大值即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=550;
ll a[maxn];
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    ll ans=0;
    for(int i=0;i<n;i++){
        for(int j=i;j<n;j++){
            for(int k=j;k<n;k++)ans=max(ans,(a[i]|a[j]|a[k]));
        }
    }
    cout<<ans<<"\n";
    return 0;
}

F - Swaps Again

题意: 问数组\(a\)是否可以通过若干次任意相等长的前缀和后缀的交换变为数组\(b\)
题解: 注意到不论多少次的交换,前缀和后缀的交换都不会变化原本值的对称性。所以我们只要判断\(a,b\)数组中的值是否以相同的值成对出现即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=550;
int a[maxn],b[maxn];
typedef pair<int,int> pii;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        vector<pii> pa(n),pb(n);
        if((n&1)&&a[n/2]!=b[n/2]){
            puts("No");
            continue;
        }
        for(int i=0;i*2<n;i++){
            if((n&1)&&i==n/2)break;
            if(a[i]>a[n-i-1])swap(a[i],a[n-i-1]);
            if(b[i]>b[n-i-1])swap(b[i],b[n-i-1]);
            pa.emplace_back(a[i],a[n-i-1]);
            pb.emplace_back(b[i],b[n-i-1]);
        }
        sort(pa.begin(),pa.end());
        sort(pb.begin(),pb.end());
        if(pa==pb)puts("Yes");
        else puts("No");
    }
    return 0;
}
posted @ 2020-06-08 14:09  Charles1999  阅读(201)  评论(0编辑  收藏  举报