牛客多校6

B Eezie and Pie

题意:给一颗树,1为根节点,树的每个节点都能向上走k步,问每个节点能被多少节点走到。

题解:树上差分,如果从6能向上继续走到3->4->1,则可在6的位置+1,在1的父节点位置-1,除此之外向上寻找能走到的最大父节点的时候需要用倍增实现

#include <bits/stdc++.h>

using namespace std;

const int N = 2e6 + 10;

int h[N], e[N << 1], ne[N << 1], idx;
int d[N], dept[N];
int fa[N][30];//从i走2^j步能到达的节点
int cnt[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void bfs()
{
    queue<int> q;
    q.push(1);
    memset(dept, 0x3f, sizeof dept);
    dept[0] = 0;
    dept[1] = 1;

    while(q.size())
    {
        int t = q.front(); q.pop();

        for(int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if(dept[j] > dept[t] + 1)
            {
                dept[j] = dept[t] + 1;
                fa[j][0] = t;
                q.push(j);
                for(int k = 1; k <= 28; k ++ )
                    fa[j][k] = fa[fa[j][k - 1]][k - 1];
               //只能向上走,而且上边的路径是完整的,所以可以边bfs边找父节点
            }
        }
    }
}

int findp(int u)
{//寻找父节点
    int len = d[u];

    for(int i = 28; i >= 0; i -- )
        if(len >= (1 << i))
            len -= (1 << i), u = fa[u][i];
            
    return u;
}

void dfs(int u, int f)
{
    cnt[u] ++;
    int p = findp(u);

    cnt[fa[p][0]] --;
    for(int i = h[u]; ~i; i = ne[i])
    {
        int t = e[i];
        if(t == f) continue;
        dfs(t, u);
        cnt[u] += cnt[t];
//差分数组相加,dfs之后u的子树t已经全部处理完毕,直接相加就行
    }
}


int main()
{
    int n; cin >> n;
    memset(h, -1, sizeof h);

    for(int i = 1; i < n; i ++ ){
        int a, b; cin >> a >> b;
        add(a, b);add(b, a);
    }
    for(int i = 1; i <= n; i ++ ) cin >> d[i];

    bfs();
    
    dfs(1, 0);

    for(int i = 1; i <= n; i ++ ) cout << cnt[i] << ' ';

    return 0;
}

M Z-Game on grid

题意:A和B走一盘棋,每次只能走到下方或者右方,A先走。A如果走到位置有‘A’的地方则A获胜,B如果走到有‘B’的地方则B获胜,如果走到(n,m)的位置还是‘.’则为平局,问B随便走,A是否能一定获胜,平局,输

题解:dp,三维状态,分别表示为从(i,j,0)出发是否能走到A,从(i,j,1)出发是否能走到B,从(i,j,2)出发是否能走到C。
横坐标+纵坐标为偶数则表示A从当前点走,否则B走。
以能否走到A为例,(i,j)的状态一定是从(i + 1, j)和(i,j + 1)转移过来,只要有一个方向能获胜则一定可以获胜,因为决定权在A手中。B就不一样了,无论B向哪个方向走,一定得赢或者输或者平局,只有一种结构,决定权实际还是在A手中。

注意:还需要处理边界,因为有&&如果现在的位置处于边界的位置,比如在第n行,只能向右走,但B需要判断下和右是不是同一个值,如果是才能置为true

#include <bits/stdc++.h>

using namespace std;

const int N = 510;

bool f[N][N][3];
//从(i,j,0)出发是否能走到A,从(i,j,1)出发是否能走到B,从(i,j,2)出发是否能走到C
char g[N][N];

int main()
{
    int t; cin >> t;

    while(t -- )
    {
        int n, m; cin >> n >> m;
        memset(f, 0, sizeof f);

        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ ){
                cin >> g[i][j];
                if(g[i][j] == 'A') f[i][j][0] = true;
                else if(g[i][j] == 'B') f[i][j][1] = true;
            }

        if(g[n][m] == '.') f[n][m][2] = true;

        for(int i = n; i >= 1; i -- ){
            for(int j = m; j >= 1; j -- ){
                if(i == n && j == m) continue;

                int st = (i + j) & 1;
                
                if(i == n){
                    f[n + 1][j][0] = f[n][j + 1][0];
                    f[n + 1][j][1] = f[n][j + 1][1];
                    f[n + 1][j][2] = f[n][j + 1][2];
                }
                if(j == m){
                    f[i][m + 1][0] = f[i + 1][m][0];
                    f[i][m + 1][1] = f[i + 1][m][1];
                    f[i][m + 1][2] = f[i + 1][m][2];
                }

                if(!st){//和为偶数,A开始走
                    if(g[i][j] == '.'){
                        f[i][j][0] = max(f[i][j][0], f[i + 1][j][0] || f[i][j + 1][0]);
                        f[i][j][1] = max(f[i][j][1], f[i + 1][j][1] || f[i][j + 1][1]);
                        f[i][j][2] = max(f[i][j][2], f[i + 1][j][2] || f[i][j + 1][2]);
                    }
                }
                else {
                    if(g[i][j] == '.'){
                        f[i][j][0] = max(f[i][j][0], f[i + 1][j][0] && f[i][j + 1][0]);
                        f[i][j][1] = max(f[i][j][1], f[i + 1][j][1] && f[i][j + 1][1]);
                        f[i][j][2] = max(f[i][j][2], f[i + 1][j][2] && f[i][j + 1][2]);
                    }//可以不用max,因为每个位置只走过一次
                }
            }
        }

        if(f[1][1][0]) cout<<"yes";
        else cout << "no";
        if(f[1][1][2]) cout << " yes";
        else cout<<" no";
        if(f[1][1][1]) cout << " yes";
        else cout << " no";

        cout<< endl;
    }

    return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值