acwing第87次周赛

58 阅读3分钟

前言

由于acwing第87次周赛是在除夕(而我当时还在抢红包),因此我就没打这次周赛,过了两天有空了,想写写水题了,就想到了这次周赛,于是就来水一水,发现这次周赛题目确实不是特别难,就水了三篇题解,QAQ。

A 移动棋子

给定一个 55 行 55 列的方格矩阵,其中一个方格中有一个棋子。

现在,我们希望将棋子移动至矩阵的最中心方格中,即将其移动至矩阵的第 33 行第 33 列方格中。

每次移动可以将棋子沿上、下、左、右任一方向移动一格距离,前提是不能移出矩阵。

请你计算,为了将棋子移动至矩阵的最中心方格中,所需要的最少移动次数。

如果棋子一开始就在最中心方格中,则无需移动。

输入格式

输入共 55 行,每行包含 55 个整数,其中第 i� 行第 j� 列的整数表示第 i� 行第 j� 列方格的状态,如果为 00,则表示该方格中没有棋子,如果为 11,则表示该方格中有棋子。

保证只有一个方格中有棋子。

输出格式

一个整数,表示所需要的最少移动次数。

数据范围

所有测试点满足,输入恰好包含 2424 个 00 和 11 个 11。

输入样例1:

0 0 0 0 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

输出样例1:

3

输入样例2:

0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0

输出样例2:

1

输入样例3:

0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0

输出样例3:

0

这是最水的一题(一如既往的水),就是找一下求的那个点到(3,3)的曼哈顿距离。

代码

#include <iostream>
#include <cmath>
using namespace std;
int main(){
    int a[6][6];
    int x,y;
    for(int i=1;i<=5;i++){
        for(int j=1;j<=5;j++){
            cin>>a[i][j];
            if(a[i][j]==1){
                x=i,y=j;
            }
        }
    }
    cout<<abs(x-3)+abs(y-3);
    return 0;
}

B 打怪兽

有 n� 个怪兽(编号 1∼n1∼�),其中第 i� 个怪兽的防御值为 ai��。

你是一个魔法师,初始时拥有 m� 点法力值。

当你的法力值大于 00 时,你可以对怪兽发动攻击,每一次攻击具体为:

  • 任意选择 1∼21∼2 个怪兽,并消耗 x� 点法力值(x� 可以是一个不超过你当前法力值的任意正整数),对每个所选怪兽发动一次伤害为 x� 的攻击。
  • 对于受到攻击的怪兽,如果其防御值小于或等于 x�,则会被你消灭。否则,它将免疫此次攻击,不受任何影响。

请你确定最大的整数 k�,满足:通过合理安排攻击,可以将第 1∼k1∼� 个怪兽全部消灭。

输入格式

第一行包含整数 n,m�,�。

第二行包含 n� 个整数 a1,a2,…,an�1,�2,…,��。

输出格式

一个整数,表示最大的整数 k�。

数据范围

前 33 个测试点满足 1≤n,m≤101≤�,�≤10。
所有测试点满足 1≤n≤10001≤�≤1000,1≤m≤1091≤�≤109,1≤ai≤m1≤��≤�。

输入样例1:

5 7
2 3 5 4 1

输出样例1:

3

这应该是这次周赛最难的题了(相较于其他题而言),题意就是说有n个数字,你现在要找一个最大的k,使得你现在的法力能消灭1-k个怪兽,然后我们每次可以选择1-2个怪兽攻击,减去最大的攻击力,最多m点攻击力,这很显然是个二分的问题,我们可以二分k的值,然后排序,再隔着取最大值,然后看值有没有m大。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int n,m;
const int N=1010;
int a[N],b[N];
bool check(int x){
    for(int i=1;i<=x;i++){
        b[i]=a[i];
    }
    b[x+1]=0;
    sort(b+1,b+x+1);
    reverse(b+1,b+x+1);
    ll ans=0;
    if(x%2==0){
        for(int i=1;i<=x;i+=2){
            ans+=b[i];
        }
    }
    else{
        for(int i=1;i<=x+1;i+=2){
            ans+=b[i];
        }
    }
    return ans<=m;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int l=1,r=n;
    while(l<r){
        int mid=l+r+1>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    cout<<l<<endl;
    return 0;
}

C 最远距离

我们规定,如果一个无向连通图满足去掉其中的任意一条边都会使得该图变得不连通,则称该图为有效无向连通图

给定一个 n� 个点 m� 条边的有效无向连通图,点的编号为 1∼n1∼�,所有边的长度均为 11。

两点之间的距离定义为两点之间的最短距离

请你计算,给定图中距离最远的两个点之间的距离。

输入格式

第一行包含两个整数 n,m�,�。

接下来 m� 行,每行包含两个整数 a,b�,�,表示点 a� 和点 b� 之间存在一条无向边。

输出格式

一个整数,表示给定图中距离最远的两个点之间的距离。

数据范围

前三个测试点满足 1≤n,m≤101≤�,�≤10。
所有测试点满足 1≤n,m≤1051≤�,�≤105,1≤a,b≤n1≤�,�≤�,a≠b�≠�。

输入样例1:

4 3
1 2
1 3
1 4

输出样例1:

2

输入样例2:

5 4
1 2
2 3
3 4
3 5

输出样例2:

3

这题就是个板子题有效无相连通图其实就是一颗树,这题就是求树的直径,板子题。

代码

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N=200100;
int n,m,idx,e[N],ne[N],w[N],h[N],ans=0;
inline void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u,int father){
    int d1=0,d2=0;
    int dist=0;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==father) continue;
        int d=dfs(j,u)+w[i];
        dist=max(dist,d);
        if(d>=d1){
            d2=d1,d1=d;
        }
        else if(d>d2){
            d2=d;
        }
    }
    ans=max(ans,d1+d2);
    return dist;
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i=1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        add(a,b,1);
        add(b,a,1);
    }
    dfs(n,-1);
    cout<<ans<<endl;
    return 0;
}