Codeforces Round #648 (Div. 2)(A~E)

A. Matrix Game(思维)

分析

  • 题意
  1. 给我们一个 有0、1构成n * m的矩阵,现在有两个人轮流进行操作,对于某次操作 当前玩家选择任意一个表格,该表中元素为0,且这个元素所在的行和列中的所有表格均没有 出现元素1, 把这个表格中的0变成1,谁先无法 进行操作谁输,问两个玩家谁能赢(他们都已最优的状态进行操作)
  • 思路
  1. 这一题看着像博弈题,但是却不是,因为当一个玩家在在进行选择表格的时候,如果有多表格都可选择的时候,其实这个时候无论他选择 对那个表格进行操作,对下个玩家所造成的影响、对答案所造成的影响都是一样的,举个例子
1 0 0
0 0 0
1 0 0
  1. 在上面这个例子中,无论当前玩家选 对(2,2)或者(2,3)进行操作,所造成的影响都是一样的,这个时候的不同选择并无优劣之分,
  2. 因此产生的思路,就是 我们提前预处理 某行、某列 是否存在1,接着我们就 模拟填数的过程,看最后 总共进行了几次操作

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e2 + 10;

int mz[mxn][mxn];
int row[mxn];
int col[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        memset(row, 0, sizeof(row));
        memset(col, 0, sizeof(col));
        int n, m;
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; i ++)        
            for(int j = 1; j <= m; j ++)
            {
                scanf("%d", &mz[i][j]);
                if(mz[i][j] == 1)
                    row[i] = 1, col[j] = 1;
            }

        int sum = 0;
        for(int i = 1; i <= n; i ++)
        {
            if(row[i] == 0)
            {
                for(int j = 1; j <= m; j ++)
                {
                    if(col[j] == 0)
                    {
                        sum ++;
                        row[i] = 1, col[j] = 1;
                        break;
                    }
                }
            }
        }

        if(sum % 2)
            printf("Ashish\n");
        else
            printf("Vivek\n");
    }

    return 0;
}

B. Trouble Sort(思维)

分析

  • 题意
  1. 给我们一个序列,这个序列中的元素值为ai,类型为bi = 0或1,如果在这个序列中 bi != bj ,我们可以交互两个数的位置,问经过若干次这样的操作之后,能否把这个序列变成 按ai值 非严格递增?
  • 思路
  1. 先说结论:
    1. 如果这个序列中既存在bi=0,又存在bj = 1的两种类型的数,就一定能够 把序列变得非严格递增,
    2. 如果仅存在类型为1或0的数的话,这个时候我们直接判读 这个序列是否为 非严格递增的,如果不是的话 输出No
  2. 我们来举个例子证明:结论1.
20 5 100 50
 0 1  1  1
  1. 在这个例子中,我们可以通过三次操作,把相同类型的两个数字 进行位置交换,
    1.
    50 5 100 20
    
    50 5 20 100
    
    20 5 50 100
    
  2. 有了例子中的这种 交换方法,我们就可以通过 它 来变化出任意我们 需要的 序列排列(递增、递减等等)情况

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
int ar[mxn], br[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        Pir fg(0,0);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &ar[i]);
        bool zeng = 1;
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d", &br[i]);
            if(br[i] == 0)
                fg.fi = 1;
            else
                fg.se = 1;
            if(ar[i] - ar[i - 1] < 0)
                zeng = 0;
        }
        if(fg.fi && fg.se)
            printf("Yes\n");
        else if(zeng)
            printf("Yes\n");
        else
            printf("No\n");
    }


    return 0;
}


C. Rotation Matching

分析

  • 题意
  1. 给我们两个数组a、b 他们的元素均在1~n之间,且每个元素仅出现一次,现在我们可以 向左向右滑动b(题目上是a数组)数组,任意k个位置,这样操作之后b数组中的元素变为:b[i] = b[(i + k)%n],问经过这样的操作之后,a与b中对应元素相同的最大数是多少?
  • 思路
  1. 既然即可以 左右都可滑动,那么我们只考虑向右滑动b数组元素 的这个操作就行了,
  2. 接着我们用桶排的方法统计出 b某个元素x,从它当前的位置i 滑动到a数组中对应的位置j需要的 需要向右滑动的距离k,这样我们统计好b中所有元素有需要的相应的滑动距离之后,,
  3. 选出 桶中 值最大的那个 值就是我们的ans

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e5 + 10;
int a[mxn], b[mxn];
int pa[mxn], pb[mxn];
int br[mxn];

int main()
{
    /* fre(); */
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]), pa[a[i]] = i;
    for(int j = 1; j <= n; j ++)
        scanf("%d", &b[j]), pb[b[j]] = j;
    
    for(int i = 1; i <= n; i ++)
    {
        br[(pa[i] - pb[i] + n) % n] ++;
    }
    int ans = 0;
    for(int i = 0; i < n; i ++)
    {
        ans = max(ans, br[i]);
    }
    printf("%d\n", ans);

    return 0;
}


D. Solve The Maze(bfs/dfs+贪心)

分析

  • 题意
  1. 给我们一个n*m的矩阵,矩阵中’.‘表示路,’#‘表示墙,‘G’、‘B’ 分别表示 好人 和坏人,现在 我们可在任意’.‘位置添加 墙’#’,问通过这个操作之后,我们能否令 好人 都能到达出口(n,m),而所有的坏人都不能到达出口
  • 思路
  1. 为了不让坏人到打出口,我们将 B 周围的四个格子都设置为 墙’#’,这样的话能够减少对路径的占用,是好人G有更大的可能到打出口,
  2. 这样我们将所有的 B的周围添加墙之后,我们桶(n,m) 跑一遍 dfs/bfs 去统计能够遍历到的人数设为sum,我们可以预统计出 G的数量设为cg,比较sum是否等于cg,如果等于的话说明所有的好人都可以到打出口,在所有的坏人都已经被墙围着的情况下

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e2 + 10;

char mz[mxn][mxn];
int mov[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
int sum = 0;
int n, m;
void dfs(int x, int y)
{
    for(int i = 0; i < 4; i ++)
    {
        int tx = x + mov[i][0];
        int ty = y + mov[i][1];
        if(tx < 1 || ty < 1 || tx > n || ty > m || mz[tx][ty] == '#') continue;
        if(mz[tx][ty] == 'G') sum ++;
        mz[tx][ty] = '#';
        dfs(tx, ty);
    }

}

bool judge(int x, int y)
{
    if(x >= 1 && y >= 1 && x <= n && y <= m && mz[x][y] == 'G')
        return true;
    return false;
}
void change(int x, int y)
{
    if(x >= 1 && y >= 1 && x <= n && y <= m && mz[x][y] != 'B')
        mz[x][y] = '#';
}

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        sum = 0;
        scanf("%d %d", &n, &m);
        int cg = 0;
        for(int i = 1; i <= n; i ++)
        {
            scanf("%s", mz[i] + 1);
            for(int j = 1; j <= m; j ++)
                if(mz[i][j] == 'G')
                    cg ++;
        }

        int fg = 1;
        for(int i = 1; i <= n; i ++)
        {
            for(int j = 1; j <= m; j ++)
                if(mz[i][j] == 'B' && judge(i, j + 1))
                {
                    fg = 0; break;
                }
                else if(mz[i][j] == 'B')
                {
                    change(i - 1, j);
                    change(i + 1, j);
                    change(i, j - 1);
                    change(i, j + 1);
                }
            if(! fg)
                break;
        }
        if(fg == 0)
        {
            printf("No\n");
            continue;
        }


        if(mz[n][m] == '#')
        {
            if(cg == 0)
                printf("Yes\n");
            else
                printf("No\n");
        }
        else
        {
            dfs(n, m);
            if(sum == cg)
                printf("Yes\n");
            else
                printf("No\n");
        }
    }


    return 0;
}


E. Maximum Subsequence Value(鸽巢原理??)

分析

  • 题意
  1. 给我们n个数我们可以从中选择人k个数,要求这个k个数中在他们对应的二进制表示中的第i位,有不少于max(1, k-2)个数在他们的二进制位上是1,那么这个第i位才是有效的1(这有效的1的在十进制下所代表的答案才能对答案有贡献),问这些总得贡献的和 最大可以是多少?
  • 思路
  1. 先说结论:在n个数中,我们只需要选择三个数(如果n<3的话就选择n个数),就能得到我们符合题意的最大和了。
  2. 证明
    1. 我们假设 n > 3, 我们从n个数中选择k(我们假设k≥3)个数,而在这个k个数中,至少有 k-2个数在二进制下第i位是1,是对答案有贡献的(也就是说在最多有两2个数在二进制下第i位为0),
    2. 如果此时,我们在从 k中选择3个数话,我们一定可确定至少有一个数在二进制下第i位位1,又因为此时max(1, 3 - 2)= 1,只要求一个数有在二进制下第i位为1,就可以对对答案产生贡献,综上3个数就可以到最大的答案了

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 2e3 + 10;
ll ar[mxn];

int main()
{
    /* fre(); */
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%lld", &ar[i]);
    ll ans = 0;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            for(int k = 1; k <= n; k ++)
                ans = max(ans, ar[i] | ar[j] | ar[k]);
    printf("%lld", ans);

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章