一、二叉树的根
什么叫二叉树?这个应该是每个人都知道的。在本题中,我们的二叉树是有根的:对于每个节点,它至多有左右两个子节点(可以为空),并且每个子树也都是二叉树。
如果无视有根二叉树中的父子关系,那么它就变成了无根树。现在我们给出任意的无根树,想让你找到这样的节点:存在某个有根二叉树的根为这个节点,且无视有根二叉树中的父子关系后,所变成的无根树恰好为给出的无根树。
由于有可能无解,也有可能有很多解,你需要对这些情况作出判断。
依题目所说,要构成二叉树,一个点连出去的边最多为3条(两个后继,一个祖先),据此可判断无解情况;而什么时候一个节点能作根呢?我们知道一个二叉树的根最多有2个后继,因而有3条连边的不可作根,其余可以。那么就可以记录每个节点的连边数,按上述分析来统计。
二、距离统计
现在有一个n×m的点阵,以这些点为顶点可以组成很多条线段。
有T次询问,每次询问给出l,求这些线段中长度为l的个数。
这题显而易见的是,当知道线段长,在纵向与横向上,我们可以用乘法原理来求解(n-l*m+m-l*n),关键在于若该长度为勾股数,那么他可以斜着安置,如图:
(3*3+4*4=5*5 长度为5时)
暴力的话可用o(根号l)枚举,但l<=1000000000000000000,(n*m),故超时。
此处转载题解:
注意:经研究发现,由于z-y为完全平方数,z-x为完全平方数2倍(y与x可互换)同时存在的(看题解最后一点证明),因而只枚举一个即可,然后得出该斜向线段覆盖的矩阵长宽,就可用((n-a)*(m-b)+(n-b)*(m-a))求解,还需判断该点阵能否容纳(⊙o⊙)哦。见程序:
01 | #include<iostream> |
02 | #include<cstdio> |
03 | #include<algorithm> |
04 | #include<cmath> |
05 | using namespace std; |
06 | int t,x,y,x1; |
07 | long long ans,n,m,a,b; |
08 | long long fan(int x){ |
09 | long long y=x; |
10 | return(y*y); |
11 | } |
12 | void did(long long x,long long y){ |
13 | if ((n>x)&&(m>y))ans+=(n-x)*(m-y)*2; |
14 | return; |
15 | } |
16 | int gcd(int x,int y){ |
17 | if (x==0)return(y); |
18 | return(gcd(y%x,x)); |
19 | } |
20 | void work(int x,int bz){ |
21 | static long long fa; |
22 | static int a; |
23 | static int b; |
24 | fa=fan(x); |
25 | for (int i=1;i<=sqrt(x);i++) |
26 | if (fan(i)!=x){ |
27 | a=x-fan(i); |
28 | b=sqrt(fan(x)-fan(a)); |
29 | if (fan(a)+fan(b)==fa) |
30 | if ((gcd(a,b)==1)&&(gcd(a,x)==1)&&(gcd(b,x)==1))did(a*bz,b*bz); |
31 | a=x-fan(i)*2; |
32 | if (a>0){ |
33 | b=sqrt(fan(x)-fan(a)); |
34 | if (fan(a)+fan(b)==fa) |
35 | if ((gcd(a,b)==1)&&(gcd(a,x)==1)&&(gcd(b,x)==1))did(a*bz,b*bz); |
36 | } |
37 | } |
38 | } |
39 | int main(){ |
40 | scanf("%d%d%d",&n,&m,&t); |
41 | for (int i=1;i<=t;i++){ |
42 | scanf("%d",&x); |
43 | ans=0; |
44 | if (i==114){ |
45 | ans=0; |
46 | } |
47 | if (n>=x)ans+=(n-x)*m; |
48 | if (m>=x)ans+=(m-x)*n; |
49 | for (int j=1;j<=sqrt(x);j++) |
50 | if (x%j==0){ |
51 | x1=x/j; |
52 | work(x1,j); |
53 | if (x1!=j){ |
54 | x1=j; |
55 | work(x1,x/j); |
56 | } |
57 | } |
58 | printf("%lld ",ans); |
59 | } |
60 | return 0; |
61 | } |
三、电阻网络
什么是电阻?这个大家应该都知道。什么是电路?大家也应该知道。但是本题当中,电路的定义或许有点不同:
电路都带有正、负极接点,正极在左,负极在右。具体地:电路分为以下几类:
单独的一个1Ω电阻(及其两端的接点)是电路。(虽然导线也可以被视为0Ω的电阻,但是单独的导线不是电路)
如果A和B都是电路,设1,2,3是从左到右的三个接点,那么将A的正负极分别接在1与2上,将B的正负极分别接在2与3上,那么1到3的部分是电路,其中1为正极,3为负极。
如果A和B都是电路,设1,2,3,2',3',1'是六个接点,其中1在2和3的左侧,2在2'的左侧,3在3'的左侧,2'和3'在1'的左侧,并且1与2,1与3,2'与1',3'与1'间均连有导线,那么将A的正负极分别接在2与2'上,将B的正负极分别接在3与3'上,那么1到1'的部分是电路,其中1为正极,1'为负极。
现在给出一个电路,求它正负极之间的电阻。
理解了电路后,我们可将连接形式分为并联、串联和混联(串+并),而串联电路电阻为:R总=U总/I总=R1+R2+R3+……,并联电阻为1/R总=1/R1+1/R2+1/R3+…
对于串联电路,我们要求出每个用电器(电阻)的电阻,而其中出现了并联,则将整个并联看做一个电阻,优先处理并联电路的电阻才能处理串联的;对于并联电路,我们要求出每个支路的电阻,而其中出现并联,由于是R总=U总/I总=R1+R2+R3+……,可以直接加过去,而遇到并联电路,则将整个并联看做一个电阻,优先处理并联电路的电阻才能处理外接的并联的。
由此,我们可以发现,当我们遇到串联时,可直接加过去,而并联时,要优先处理,形成一个优先级别,可以用栈进行处理,这样就可以的出解法:
遇到串联时,直接加过去,遇到并联起点,新开一个栈,遇到并联终点时,将各支路电阻倒数求和再倒数,由于具有传递性和单向性,我们可以将电阻值储存在接点上,一个个点转移,见程序:
01 | #include<cstdio> |
02 | #include<algorithm> |
03 | #include<iostream> |
04 | #include<iomanip> |
05 | using namespace std; |
06 | int n,m,l,r,sum; |
07 | double a[100001],h[100001]; |
08 | double q; |
09 | int e[500001][3],g[100001],b[100001],c[100001],d[100001],f[100001]; |
10 | void in(int x,int y,int z){ |
11 | e[++sum][0]=y; |
12 | e[sum][1]=z; |
13 | e[sum][2]=g[x]; |
14 | g[x]=sum; |
15 | } |
16 | void work(){ |
17 | int x; |
18 | if (c[d[r]]>1)h[++sum]=a[d[r]]; |
19 | while (!((g[d[1]]==0)&&(r==1))){ |
20 | if (g[d[r]]!=0){ |
21 | x=g[d[r]]; |
22 | if (b[e[x][0]]>1){ |
23 | q=a[d[r]]+e[x][1]; |
24 | if (q!=0) |
25 | a[e[x][0]]+=1/q; |
26 | }else {if (e[x][1]==1)a[e[x][0]]++; |
27 | a[e[x][0]]+=a[d[r]];} |
28 | g[d[r]]=e[x][2]; |
29 | d[++r]=e[x][0]; |
30 | f[d[r]]++; |
31 | if (f[d[r]]==b[d[r]]){ |
32 | if ((b[d[r]]==f[d[r]])&&(b[d[r]]>1)){ |
33 | if (a[d[r]]!=0)a[d[r]]=1/a[d[r]]+h[sum];else a[d[r]]=h[sum]; |
34 | sum--; |
35 | } |
36 | if (c[d[r]]>1){h[++sum]=a[d[r]];a[d[r]]=0;} |
37 | }else r--; |
38 | }else r--; |
39 | } |
40 | } |
41 | int main(){ |
42 | scanf("%d %d",&n,&m); |
43 | int x,y,z; |
44 | for (int i=1;i<=m;i++){ |
45 | scanf("%d %d %d",&x,&y,&z); |
46 | in(x,y,z); |
47 | b[y]++;c[x]++; |
48 | } |
49 | sum=0; |
50 | for (int i=1;i<=n;i++) |
51 | if (b[i]==0){ |
52 | r++; |
53 | d[r]=i; |
54 | break; |
55 | } |
56 | work(); |
57 | printf("%.3f",a[n]); |
58 | return 0; |
59 | } |