Educoder 题解
Solution
4.2:
第一关:
求个导发现有两个根,分别二分就行了
import numpy as np E = 1e-6 ########## begin ########## # 请在此填写代码, 计算6*np.exp(x)-113*x+17=0的根 def f(x): return 6*np.exp(x)-113*x+17 def divd(L,R): while(L<R): mid=(L+R)/2 if(abs(f(mid))<=E): return mid if(f(mid)<-E): R=mid else: L=mid def div(L,R): while(L<R): mid=(L+R)/2 if(abs(f(mid))<=E): return mid if(f(mid)>-E): R=mid else: L=mid print("%.4f"%divd(0,1.0)) print("%.4f"%div(4.0,5.0)) ########## end ##########
第二关:
不难发现h的值依赖于角度θ,且θ满足sinθ/θ=L/S,即S×sinθ/θ-L=0 对该式求导,发现其单减,且显然0<θ<π/2,故二分求θ即可
又因为有h=L/2*tan(θ/2),这样就做完了
from math import * L, n, C = map(float, input().split()) E=1e-8 S=(1+n*C)*L def divd(l,r): while(l<r): mid=(l+r)/2 val=S*sin(mid)/mid-L if(abs(val)<=E): return mid if(val<-E): r=mid else: l=mid t=divd(0,pi/2) h=L/2*tan(t/2) ########## begin ########## # 请在此填写代码,求方程的根 ########## end ########## print('%.4f' % h)
4.3:
第一关:
显然由某一个点出发的最小积依赖于由他下方点出发的最小积或右下方出发的最小积,取二者中的最小值
n = eval(input()) dp=[] for i in range(n): X = dp.append(list(map(int, input().split()))) for i in range(n-2,0,-1): for j in range(0,i+1,1): dp[i][j]*=min(dp[i+1][j+1],dp[i+1][j]) dp[0][0]*=min(dp[1][0],dp[1][1]) print(dp[0][0]
第二关:
递归太麻烦了,for循坏可以O(n)搞完,效率更高还好写
dp[i]表示以i为起点的最大子序列积,有dp[i]=max(dp[i+1]×A[i],dp[i])(分别对应将A[i]加入以A[i+1]为起始的最大子序列或不加入单独考虑)
最末尾显然只能单独考虑,有dp[n-1]=A[n-1],倒序for一遍,再取最大的dp[i]即可
代码中把A列表和dp列表共用了,不影响正确性
n = eval(input()) A= list(map(float, input().split())) for i in range(n-2,0,-1): A[i]=max(A[i],A[i+1]*A[i]) A[0]=max(A[0],A[1]*A[0]) ans=0.0 for i in range(0,n,1): ans=max(ans,A[i]) print("%.2f"%(ans)
4.4:
第一题的话,考虑归并,先二分再合并,合并时注意两个子点集之间的配对情况
第二题,实际上和第一题一样,只不过处理的时候注意一下两个点的分组情况,只有不同组的时候才需要处理
第一关:
from math import * n = eval(input()) A=[] for i in range(n): x,y= map(int, input().split()) A.append((x,y)) def Distance(a, b): return sqrt((a[0]-b[0])**2+(a[1]-b[1])**2) #求[low..high]区间内的最小点距 def FidMin(A,L,R): ########## begin ########## # 请在此填写代码,返回区间[low,high]的最小点距 mid=(L+R)//2 if(L==R): return 1e9 if(L==R-1): return Distance(A[L],A[R]) d=min(FidMin(A,L,mid),FidMin(A,mid+1,R)) tmp=[] p0=A[mid] for i in range(L,R+1,1): p1=A[i] if(abs(p1[0]-p0[0])=d): break d=min(d,Distance(tmp[i],tmp[j])) return d ########## end ########## A.sort() result=FidMin(A,0,len(A)-1) print('%.3f' % result)
第二关:
import math n = eval(input()) A=[] for i in range(n*2): group = 1 if i<n else 2 x,y= map(int, input().split()) A.append((x,y,group)) def Distance(a, b): return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2) #求[low..high]区间内的最小点距 def FidMin(A,L,R): ########## begin ########## # 请在此填写代码,返回区间[low,high]的最小点距,且这两点属于不同的组 mid=(L+R)//2 if(L==R): return 1e9 if((L==R-1) and (A[L][2]==A[R][2])): return 1e9 if(L==R-1): return Distance(A[L],A[R]) d=min(FidMin(A,L,mid),FidMin(A,mid+1,R)) tmp=[] p0=A[mid] for i in range(L,R+1,1): p1=A[i] if(abs(p1[0]-p0[0])<d): tmp.append(p1) tmp.sort(key=lambda x:x[1]) upp=len(tmp)-1 for i in range(0,upp+1,1): for j in range(i+1,upp+1,1): if(abs(tmp[i][1]-tmp[j][1])>=d): break if(tmp[i][2]!=tmp[j][2]): d=min(d,Distance(tmp[i],tmp[j])) return d ########## end ########## A.sort() result=FidMin(A,0,len(A)-1) print('%.3f' % result)
4.5:
第一关:
递归就行了,先序遍历,每访问一个点答案+1
def CalcNodes(tree): ########## begin ########## # 请在此填写代码 if(len(tree)==0): return 0 return 1+CalcNodes(tree[1])+CalcNodes(tree[2]) ########## end ##########
第二关:
中序中,根节点所在位置左边的序列就是左子树的中序序列,右边就是右子树的中序序列
然后先序序列其实就是根+左子树的先序序列+右子树的先序序列
后序序列是左子树后序+右子树后序+根
#pre_order:先根序列 in_order:中根序列 #要求返回后跟序列 def get_postorder(pre_order, in_order): ########## begin ########## # 请在此填写代码 l=len(in_order) if(l==0): return '' root=pre_order[0] if(l==1): return root for i in range(0,l,1): if(in_order[i]==root): pos=i break pol='' por='' iol='' ior='' for i in range(1,1+pos,1): pol=pol+pre_order[i] for i in range(1+pos,l,1): por=por+pre_order[i] for i in range(0,pos,1): iol=iol+in_order[i] for i in range(pos+1,l,1): ior=ior+in_order[i] p1=get_postorder(por,ior) p2=get_postorder(pol,iol) return p2+p1+root ########## end ##########
4.6:
第一关:
由于本题我们只关心序列的合法性,对于左括号,入栈,对于右括号,不必入栈,只需要与栈顶的左括号相匹配,匹配成功就继续处理下一个括号,失败就直接输出false
全部括号都处理完成后,如果栈内仍有未匹配的左括号,还是输出false
在处理过程中,记得留意空栈的情况
from queue import LifoQueue #括号匹配 S=input() #输入的字符串 sta=[] ########## begin ########## # 请在此填写代码 tot=0 ans=True def match(x,y): if(x=='[' and y==']'): return True if(x=='(' and y==')'): return True if(x=='{' and y=='}'): return True return False for i in S: if(i=='[' or i=='(' or i=='{'): sta.append(i) tot+=1 else: if(tot==0): ans=False break if(match(sta[tot-1],i)): del sta[tot-1] tot-=1 else: ans=False break if(tot!=0): ans=False print(ans)
第二关:
与上一关有些不同,栈里维护的是括号在原字符串的索引而不是括号本身
新增一个ok列表,ok[i]表示第i位的括号是否匹配成功,ok[i]=1表示成功,ok[i]=0则是失败
匹配方法则与第一关类似,但因为需要计数,所以这里右括号也要入栈
最开始ok[i]均设为0,匹配成功,把这组左右括号对应的ok[i]改为1
答案就是ok[i]列表中最长的连续为1的子段的长度
复杂度O(n)
from queue import LifoQueue #括号匹配 S=input() #输入的字符串 sta=[] ok=[] ########## begin ########## # 请在此填写代码 tot=0 ans=0 cnt=0 def match(x,y): if(x=='[' and y==']'): return True if(x=='(' and y==')'): return True if(x=='{' and y=='}'): return True return False l=len(S) for i in range(0,l,1): ok.append(0); for i in range(0,l,1): if(S[i]=='[' or S[i]=='(' or S[i]=='{'): sta.append(i) tot+=1 else: if(tot==0): sta.append(i) tot+=1 elif(match(S[sta[tot-1]],S[i])): ok[i]=1 ok[sta[tot-1]]=1 del sta[tot-1] tot-=1 else: sta.append(i) tot+=1 for i in range(0,l,1): if(ok[i]==1): cnt+=1 ans=max(ans,cnt) else: cnt=0 print(ans)