"蔚来杯"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] 个点。
求对于每个点,会被多少个点遍历到。
思路:
如果可以快速找出每个点的 级祖先,我们就可以用树上差分来求出最终的价值。
我们可以利用LCA中的树上倍增,在的复杂度求出 级祖先。
当然也可以使用树链剖分
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在玩游戏,初始有一个棋子在 上,二人轮流操作棋子,每次可以选择向下和向右,不能出界。
- 遇到A,Alice胜,
- 遇到B,Bob胜
- 如果一直到了 ,则平局。
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; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16573254.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步