"蔚来杯"2022牛客暑期多校训练营6补题 J , G , B , M

J Number Game 签到

推公式即可

代码:

#include <bits/stdc++.h>
#define endl '\n'
// #define int long long
using namespace std;
const int N = 205, M = 805;
int n, m;
int a[N], b[N];
int dp[N][21][M];
void solve()
{
   int a,b,c,d;
   cin>>a>>b>>c>>d;
   int b1=a-b;
   int b2=b;
   int ans11=b1-c;
   int ans12=b2-c;
   int ans13=c;
   int flag=0;
   if(ans13==d||ans12==d||ans11==d) flag=1;
{
      if(flag)    
   cout<<"Yes"<<endl;
   else cout<<"No"<<endl;
   return;
}

   int cnt=d-c;

   int k1=a-2*b;
   int ans1=cnt/k1;
   if(ans1*k1==cnt&& ans1>=0) flag=1;


   
   int k2=2*b-a;
   int ans2=cnt/k2;
   if(ans2*k2==cnt && ans2>=0) flag=1;

   if(flag)    
   cout<<"Yes"<<endl;
   else cout<<"No"<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

G Icon Design 耐心题

n=5,直接打表

void solve(){
    cin >> n;
    for(int i = 1; i <= 4 * n + 5; i++){
        for(int j = 1; j <= 13 * n + 19; j++){
            if(i == 1 || i == 4 * n + 5){
                cout <<"*";
            }
            else if(i <= 1 + n){
                if(j == 1 || j == 13 * n + 19) cout <<"*";
                else cout <<".";
            }
            else if(i <= 1 + n + 2 * n + 3){
                if(j == 1 || j == 13 * n + 19) cout << "*";
                else if(j <= 1 + n + 1) cout <<".";
                else if(j <= 1 + n + 1 + 2 * n + 3){
                    if(j == 1 + n + 1 + 1 || j == 1 + n + 1 + 2 * n + 3){
                        cout <<"@";
                    }
                    else if(i == j - 1){
                        cout <<"@";
                    }
                    else cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1){
                    cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3){
                    if(j == 1 + 1 + n + 2 * n + 3 + n + 1 + 1) cout <<"@";
                    else if(i == 1 + n + 1) cout <<"@";
                    else if(i == 1 + n + n + 2) cout <<"@";
                    else cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1){
                    cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3){
                    if(j == 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 1){
                        cout <<"@";
                    }
                    else if(i == n + 1 + 2 * n + 3) cout <<"@";
                    else cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1){
                    cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3){
                    if(i == 1 + n + 1){
                        cout <<"@";
                    }
                    else if(i <= 1 + n + n + 1 && j == 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 1) cout <<"@";
                    else if(i == 1 + n + n + 1 + 1) cout <<"@";
                    else if(i >= n + 1 + n + 2 && i <= n + 1 + 2 * n + 3- 1 && j == 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3){
                        cout <<"@";
                    }
                    else if(i == 1 + n + 2 * n + 3){
                        cout <<"@";
                    }
                    else cout <<".";
                }
                else if(j <= 1 + 1 + n + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1 + 2 * n + 3 + n + 1){
                    cout <<".";
                }
                else cout <<"*";
            }
            else if(i <= 1 + n + 2 * n + 3 + n + 1){
                if(j == 1 || j == 13 * n + 19){
                    cout <<"*";
                }
                else cout <<".";
            }
            //else if(i == 4 * n + 5)cout <<"*";
        }
        cout << endl;
    }
}

B Eezie and Pie 树上差分 LCA

题意:
给出一棵的树,以1为根。每个点都有点权 d[i]。
对于点 i ,你需要在从 i点出现,向上跑 d[i] 个点。

求对于每个点,会多少个点遍历到。

思路:
如果可以快速找出每个点的 \(k\) 级祖先,我们就可以用树上差分来求出最终的价值。

我们可以利用LCA中的树上倍增,在\(O(nlogn)\)的复杂度求出 \(k\) 级祖先。
当然也可以使用树链剖分

DFS代码:

#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10,M=2*N;
int n;
int cnt[N];
int to[M],pre[M], h[N],idx;
int fa[N][21],dep[N];
int d[N];
int ans[N];
void add(int a,int b){
    to[idx]=b,pre[idx]=h[a],h[a]=idx++;
}
void dfs_lca(int u,int father){
    dep[u]=dep[father]+1;
    fa[u][0]=father;
    for(int i=1;(1<<i)<=dep[u];i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=h[u];i!=-1;i=pre[i]){
        int j=to[i];
        if(j!=father){
             dfs_lca(j,u);
        }
    }    
}
int  get_fa(int u,int k){
    if(k==0) return u;
    int temp=dep[u]-k;
    for(int i=20;i>=0;i--)
        if(dep[fa[u][i]]>temp)
            u=fa[u][i];
    return fa[u][0];
}

int dfs(int u,int father){
    int res=d[u];
     for(int i=h[u];i!=-1;i=pre[i]){
        int j=to[i];
        if(j!=father){
             res+=dfs(j,u);
        }
    }    
    ans[u]=res;
  return res;
}

void solve(){
    memset(h,-1,sizeof h);
   cin>>n;
   for(int i=0;i<n-1;i++){
       int u ,v;cin>>u>>v;
       add(u,v),add(v,u);
   }
   for(int i=1;i<=n;i++){
    cin>>cnt[i];
   }
   dfs_lca(1,0);
   for(int i=1;i<=n;i++){
      d[i]++;
      d[get_fa(i,max(0,cnt[i]+1))]--;
 }

   dfs(1,0);
   for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
   cout<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    // cin>>t;
    while(t--) 
        solve();
    return 0;
}

BFS代码

BFS思路:将叶子节点放进去,从叶子节点BFS。
BFS有个注意点:要使用优先队列,保证严格的层次遍历。

const int N = 2e6 + 10;
int n, a[N];
int dep[N],fa[N][23];
vector<int> g[N];
int cnt[N], d[N], f[N];
bool vis[N];

void dfs(int x,int f){
    dep[x]=dep[f]+1;
    fa[x][0]=f;
    for(int i=1;(1<<i)<=dep[x];i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int t: g[x]){
        if(t!=f){
            dfs(t,x);
        }
    }
}
int getfa(int x,int k){
      if(k==0) return x;
    int t=dep[x]-k;
    for(int i=21;i>=0;i--){
        if(dep[fa[x][i]]>t)
             x=fa[x][i];
    }
  
    // if(fa[x][0]==0) return 1;
    return fa[x][0];
}

void bfs(){
    priority_queue<pii> q;//节点
    for(int i = 2; i <= n; i++){
        if(g[i].size() == 1){
            q.push({dep[i],i});
        }
    }
    while(!q.empty()){
        pii t = q.top();
        q.pop();
        int x = t.sec;
        int u = f[x];
        cnt[u] += cnt[x];
        if(!vis[u]){
            q.push({dep[u], u});
            vis[u] = 1;
        }
    }
}

void solve(){
    cin >> n;
    for(int i = 1; i <= n-1; i++){
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++){
        int f1 = getfa(i, 1);
        int f2 = getfa(f1, a[i]);
        f[i] = f1;
        cnt[f2] --;
        cnt[f1] ++;
    }
    bfs();
    for(int i = 1; i <= n; i++){
        if(i == 1) cout << cnt[i] + 1;
        else cout <<" " << cnt[i] + 1;
    }
}

官方题解:DFS栈

维护 dfs 栈,快速求出一个点的 𝑘 级祖先

在 dfs 时维护 dfs 栈,那么访问到点 𝑖 时,它的 𝑘 级祖先一定在当前栈内向下 𝑘 个。利用这个性质,可以 𝑂(𝑁) 求出所有的祖先。

代码:

void dfs_fa(int u,int father)
{
    stk[++top]=u;
    d[u]+=1;
    d[stk[max(0,top-cnt[u]-1)]]-=1;

    for(int i=h[u]; i!=-1; i=pre[i])
    {
        int j=to[i];
        if(j!=father)
            dfs_fa(j,u);
    }

    top--;
}

M Z-Game on grid 博弈论 DP

题意:
给定一个矩阵,上面有'A', 'B' 和 '.' 三种字符。

Alice和Bob在玩游戏,初始有一个棋子在 \((1,1)\)上,二人轮流操作棋子,每次可以选择向下和向右,不能出界。

  • 遇到A,Alice胜,
  • 遇到B,Bob胜
  • 如果一直到了 \((n,m)\),则平局。

Alice先手。
问Alice是否有必胜、必平局、必败的策略。

思路:
我们枚举三次Alice想要的状态,设置为 k.

对于非 k 的状态,就是Alice不想要的。

并且,对于矩阵上的点(r,c),我们一定可以知道这个时候是谁在操作。

(因为 (1,1) 到 (r,c) 的操作数是固定的)

  • 如果是Alice操作,两个方向可以获得的状态为 cnt1,cnt2。
    只要这里有一个方向是Alice想要的,那么Alice就会走向它。

  • 如果是Bob来操作,只要有一个方向不是k的,Bob就会选择这个方向。

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
const int N = 510;
int n, m;
char a[N][N];
int k;
int dp[N][N];
bool check(int r, int c)
{ //检查是否越界
    return 1 <= r && r <= n && 1 <= c && c <= m;
}
int dfs(int r, int c)
{
    if (a[r][c] == 'A')
        return 1;
    if (a[r][c] == 'B')
        return 2;
    if (r == n && c == m)
        return 3;
    if (dp[r][c] != -1)
        return dp[r][c];
    // A
    if ((r + c) % 2 == 0)
    {
        int cnt1 = 0, cnt2 = 0;
        if (check(r + 1, c))
        {
            cnt1 = dfs(r + 1, c);
            if (cnt1 == k)
                return dp[r][c] = k;
        }
        if (check(r, c + 1))
        {
            cnt2 = dfs(r, c + 1);
            if (cnt2 == k)
                return dp[r][c] = k;
        }
        if (cnt1 == 0)
            return dp[r][c] = cnt2;
        else
            return dp[r][c] = cnt1;
    }
    // B
    else
    {
        int cnt1 = 0, cnt2 = 0;
        if (check(r + 1, c))
        {
            cnt1 = dfs(r + 1, c);
            if (cnt1 != k)
                return dp[r][c] = cnt1;
        }
        if (check(r, c + 1))
        {
            cnt2 = dfs(r, c + 1);
            if (cnt2 != k)
                return dp[r][c] = cnt2;
        }
        if (cnt1 == 0)
            return dp[r][c] = cnt2;
        else
            return dp[r][c] = cnt1;
    }
}
void init()
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            dp[i][j] = -1;
}

void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i] + 1;

    k = 1;
    init();
    if (dfs(1, 1) == k)
        cout << "yes ";
    else
        cout << "no ";

    k = 3;
    init();
    if (dfs(1, 1) == k)
        cout << "yes ";
    else
        cout << "no ";

    k = 2;
    init();
    if (dfs(1, 1) == k)
        cout << "yes";
    else
        cout << "no";
    cout << endl;
}

signed main()
{
    int t = 1;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

参考

posted @ 2022-08-10 20:15  kingwzun  阅读(24)  评论(0编辑  收藏  举报