0 简介
0-1 关于文章
这是 AtCoder Beginner Contest 276 的解释。
该实现是用 Python 和 C++ 编写的。
请注意,可能与官方解释存在差异。
如果您发现任何错误,请在评论部分告诉我。
1 ABC276 评论
1-1 个人印象
这次我也过不了F。
Diff就像A是早灰,B是晚灰,C是中灰棕,D是晚棕,E是晚绿,F是晚水。
看起来不像上周?我认同。
我想通过后半段水。
1-2 问题 A 最右边
问题
您将获得一个小写字符串 $S$。
从 $S$ 的左边算起 $S$ 中最右边的a 的编号。
如果a 不包含在$S$ 中,则输出-1。
约束
・$1 列克 |S| 列克 100$
评论
它可以通过执行一个操作来解决,该操作将for 句子围绕S 旋转并在您正在查看的字符是a 时更新答案。
如果从未更新,则输出-1,否则输出答案。
输出时不要忘记使用1-indexed。
Python中的实现示例
S=input()
ans=-1
for i in range(len(S)):
if S[i]=="a":
ans=i+1
print(ans)
请注意,Python 中的 S.index(n) 返回 S 中包含的第一个 n 的 index。
(如果字符串颠倒了也可以使用..)
C++中的实现示例
#include <bits/stdc++.h>
using namespace std;
#define rep(i,N,M) for(int i=N; i<M; i++)
int main(){
string S; cin>>S;
int l=S.size();
int ans=-1;
rep(i,0,l){
if(S[i]=='a'){
ans=i+1;
}
}
cout<<ans<<endl;
}
1-3 问题B邻接表
问题
有 $N$ 个城市,编号为 $1,2,...,N$ 和 $M$ 路连接它们。
第$i$条路连接$A_i、B_i$城市,$A_i、B_i$可以相互通行。
为 $k(1 leq k leq N)$ 打印以下内容。
与城市$k$直接相连的城市$d_k$的数量,以及这些城市编号升序排列的序列$a_k$
约束
・$2 leq N leq 10^5$
・$1 leq M leq 10^5$
・$1 leq A_i < B_i leq N$
・$(A_i,B_i)$ 不同评论
准备一个数组$L_i$,存储与城市$i$直接相连的城市,进入时记下。令 $L$ 是一个二维数组。
输入完成后,排序输出。Python中的实现示例
N,M=map(int,input().split()) L=[[] for _ in range(N+1)] for i in range(M): a,b=map(int,input().split()) L[a].append(b); L[b].append(a) for i in range(N): print(len(L[i+1]),*sorted(L[i+1]),sep=" ")C++中的实现示例
#include <bits/stdc++.h> using namespace std; #define rep(i,N,M) for(int i=N; i<M; i++) int main(){ int N,M; cin>>N>>M; vector<vector<int>> L(N+1); rep(i,0,M){ int a,b; cin>>a>>b; L[a].push_back(b); L[b].push_back(a); } rep(i,1,N+1){ int n=L[i].size(); cout<<n<<" "; sort(L[i].begin(),L[i].end()); rep(j,0,n){ cout<<L[i][j]; if(j!=n-1){ cout<<" "; }else{ cout<<endl; } } } }用存储连接到顶点 $i$ 的顶点的二维数组表示图称为邻接矩阵表示。
这是大多数图形问题的输入,所以让我们记住它。1-4 问题 C 上一个排列
问题
给定 $(1,2,...,N)$ 的排列 $P$。
当 $(1,2,...,N)$ 的所有排列按字典顺序排列时,输出 $P$ 之前的排列。
保证存在 $(1,2,...,N)$ 的排列,按字典顺序排列在 $P$ 之前。约束
・$1 leq N leq 100$
评论
天真地列举 $(1,2,...,N)$ 的排列需要 $O(N!)$,考虑到我们的限制,这是不计后果的。
让我们考虑如何从给定的排列 $P$ 中找到所需的排列 $Q$。考虑重新排列 $P$ 以产生 $Q$。
最好尽量减少 $P$ 的向左变化。
如果要改变右边的$n$项,只有当$P$右边的$n$项单调递增时,才需要改变$P$右边的$n$项。
以输入/输出例子2为例,$A=(9,8,6,5,10,3,1,2,4,7)$的前一个排列是$B=(9,8, 6, 5,10,2,7,4,3,1)$。
由于$(1,2,4,7)$是单调递增的,即使重新排列也不能按字典序变小,可以像$(2,7,4,3,1)$那样按字典序变小。
并且如上图所示,$P$右边的$n$项中最左边的$3$是$(1,2,3,4,7)$中的$3$之后的第二小。它变为$2$,单调递增的部分单调递减。 .
换句话说,您应该实现这一点。
(1) 找到$i$ 项从$A$ 的右侧单调递增的最大$i$,并将其设为$n$。
(2)在$A$右边的$n$个项目中,找到$A$右边的$n$个项目之后的下一个最小的数字,并将其索引设置为$m$。
(3)从$A$的右边交换$n$项和$A_m$,从右边反转$n-1$项。所有这些操作都可以在$O(N)$中完成,因此总计算复杂度为$O(N log N)$。
实现“右边的 $i$ 项”使实现复杂化。
Python中的实现示例
N=int(input()) P=list(map(int,input().split())) n=N-2 #P[n]より右は単調増加 while P[n]<P[n+1]: n-=1 m=N-1 #P[n]より右にある、P[n]未満の最小 while P[n]<P[m]: m-=1 P[n],P[m]=P[m],P[n] #P[n],P[m]を交換 ans=P[:n+1]+P[n+1:][::-1] #P[n]より左はそのまま、P[n]以右は反転させる print(*ans)C++中的实现示例
#include <bits/stdc++.h> using namespace std; #define rep(i,N,M) for(int i=N; i<M; i++) int main(){ int N; cin>>N; vector<int> P(N); rep(i,0,N) cin>>P[i]; int n=N-2; while(P[n]<P[n+1]){ n--; } int m=N-1; while(P[n]<P[m]){ m--; } swap(P[n],P[m]); reverse(P.begin()+n+1,P.end()); rep(i,0,N){ cout<<P[i]; if(i==N-1){ cout<<endl; }else{ cout<<" "; } } }它已经完全向后兼容官方评论......
作为旁注
似乎 C++ 在标准库中有一个名为
prev_permutation的类似作弊的函数,它按字典顺序返回先前的排列。我生气C++ 中的实现示例(`prev_permutation`)
#include <bits/stdc++.h> using namespace std; #define rep(i,N,M) for(int i=N; i<M; i++) int main(){ int N; cin>>N; vector<int> P(N); rep(i,0,N) cin>>P[i]; prev_permutation(P.begin(),P.end()); rep(i,0,N){ cout<<P[i]; if(i==N-1){ cout<<endl; }else{ cout<<" "; } } }1-5 D 题 除以 2 或 3
问题
给定一个长度为 $N$ 的整数序列 $A$。
您可以多次执行以下操作。(1) 选择一个$A_i$,它是$2$ 的倍数,并将其替换为$ frac {A_i}{2}$。
②选择一个$A_i$,它是$3$ 的倍数,并替换为$ frac {A_i}{3}$。我希望这个操作能够均衡 $A$ 的所有元素。
找出为此目的所需的最少操作数。约束
评论
当所有$A$ 相等时,$A_i$ 的值是$A$ 的公约数。
并且$A_i$在运算时成为$A$的最大公约数,从而使运算次数最小化。因此,您应该执行以下操作:
① 求$A$ 的最大公约数$g$。
② 对于每个 $ frac{A_i}{g}$,求它除以 $2$ 或 $3$ 的次数得到 $1$。这些值的总和就是答案。如果甚至有一件事不能是 $1$,那么答案就是 $-1$。第①部分的计算复杂度为$O(N log max A)$。
第 2 部分是 $O(N log max A)$,因为我们将每个 $frac{A_i}{g}$ 除以 $2$ 或 $3$。最大公约数的复杂度
在这里,我们将解释找到 $2$ 自然数 $A,B$ 的最大公约数的计算量。
目前已知的求最大公约数的最有效方法是欧几里得除法。
随着我们继续进行欧几里德除法,两个数字 $A 和 B$ 会呈指数级变小。
当执行 $2$ 步骤时,$A 和 B$ 总是小于彼此的一半。
所以复杂度是$O(log min (A,B))$。因此,总计算复杂度为$O(N log max A)$。
Python中的实现示例
from math import gcd N=int(input()) A=list(map(int,input().split())) g=0 for i in range(N): g=gcd(g,A[i]) ans=0 for i in range(N): now=A[i]//g while now%2==0: now//=2 ans+=1 while now%3==0: now//=3 ans+=1 if now!=1: print(-1); exit() print(ans)C++中的实现示例
#include <bits/stdc++.h> using namespace std; #define rep(i,N,M) for(int i=N; i<M; i++) int main(){ int N; cin>>N; vector<int> A(N); rep(i,0,N) cin>>A[i]; int g=0; rep(i,0,N){ g=gcd(g,A[i]); } int ans=0; rep(i,0,N){ int now=A[i]/g; while(now%2==0){ now/=2; ans++; } while(now%3==0){ now/=3; ans++; } if(now!=1){ cout<<-1<<endl; return 0; } } cout<<ans<<endl; }1-6 E 问题往返
问题
有$H×W$个正方形,从上数第$i$行和从左数第$j$列的正方形表示为$(i,j)$。
每个方格要么是起点(S),要么是道路(.),要么是障碍物(#),不能去有障碍物的方格。
从起点出发,上下左右,返回起点,判断是否有一条长度为$4$以上的路径除了第一个和最后一个不经过同一个方格。 .约束
・$2 leq H, W $
・$4 leq H×W leq 10^6$评论
首先,让我们考虑一下“路线”。
路线为起点→起点相邻的道路$A$→起点相邻的道路$B$→返回起点。
这里,对于与起点相邻的任意路径$A和B$,如果$A和B$可以在起点以外的地方进出,那么总会有一条长度为$4$或更长的路径。证明
“起点→起点和相邻路径$A$”和“起点和相邻路径$B$→起点”的长度都是$1$。
如果您可以从 $A$ 到 $B$,则与起点相邻的任何道路 $A 和 B$ 必须是 $2$ 或更多。因为$A 和B$ 不能相邻。
因此,“路径”长度大于$1+1+2=4$。这使得解决决策问题变得容易。
对于 $(A,B)$(最多 $6$)的所有可能路径对,检查 $A$ 和 $B$ 是否经过起点以外的路径就足够了。可以使用以下方法回答
BFS的计算量为$O(HW)$,UnionFind的计算量为$O(HW)$,因为查询基本上可以在$O(1)$中处理。 .
实现是在 BFS 中完成的。
Python中的实现示例
from collections import deque H,W=map(int,input().split()) C=[list(input()) for _ in range(H)] sx,sy=0,0 for i in range(H): for j in range(W): if C[i][j]=="S": sx,sy=i,j dir=[[0,-1],[0,1],[-1,0],[1,0]] ok=lambda x,y:0<=x<H and 0<=y<W and C[x][y]=="." def BFS(X,Y): D=deque(); D.append((X,Y)) dist=[[-1]*W for _ in range(H)]; dist[X][Y]=0 while D: x,y=D.popleft() for a,b in dir: nx,ny=x+a,y+b if not (ok(nx,ny) and dist[nx][ny]==-1): continue dist[nx][ny]=dist[x][y]+1 D.append((nx,ny)) return dist l=[] for a,b in dir: x,y=sx+a,sy+b if ok(x,y): l.append((x,y)) for i in range(len(l)): x,y=l[i] dist=BFS(x,y) for j in range(i+1,len(l)): nx,ny=l[j] if dist[nx][ny]!=-1: print("Yes") exit() print("No")实施起来是不是太难了?C++中的实现示例
#include <bits/stdc++.h> using namespace std; #define rep(i,N,M) for(int i=N; i<M; i++) int H,W; vector<string> C(1000000); vector<pair<int,int>> dir={{0,-1},{0,1},{-1,0},{1,0}}; bool ok(int x,int y){ return 0<=x and x<H and 0<=y and y<W and C[x][y]=='.'; } vector<vector<int>> BFS(int X,int Y){ deque<pair<int,int>> D; D.push_back(make_pair(X,Y)); vector<vector<int>> dist(H,vector<int>(W,-1)); dist[X][Y]=0; while(!D.empty()){ int x,y; tie(x,y)=D.front(); D.pop_front(); rep(i,0,4){ int a,b; tie(a,b)=dir[i]; int nx=x+a,ny=y+b; if(ok(nx,ny) and dist[nx][ny]==-1){ dist[nx][ny]=dist[x][y]+1; D.push_back(make_pair(nx,ny)); } } } return dist; } int main(){ cin>>H>>W; int sx=0,sy=0; rep(i,0,H){ cin>>C[i]; rep(j,0,W){ if(C[i][j]=='S'){ sx=i; sy=j; } } } vector<pair<int,int>> l; rep(i,0,4){ int a,b; tie(a,b)=dir[i]; int nx=sx+a,ny=sy+b; if(ok(nx,ny)){ l.push_back(make_pair(nx,ny)); } } int n=l.size(); rep(i,0,n){ int ax,ay; tie(ax,ay)=l[i]; vector<vector<int>> dist=BFS(ax,ay); rep(j,i+1,n){ int bx,by; tie(bx,by)=l[j]; if(ok(bx,by) and dist[bx][by]!=-1){ cout<<"Yes"<<endl; return 0; } } } cout<<"No"<<endl; }1-7 F 问题双重机会
问题
我稍后会解释。
2 最后
感谢您阅读到最后。
这段时间一定很艰难。
我很惊讶 C 几乎是灰烬 Diff。
就这样。
非常感谢。
有一个良好的职业竞争生活!请喜欢...
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308633153.html