一、二叉树的根
什么叫二叉树?这个应该是每个人都知道的。在本题中,我们的二叉树是有根的:对于每个节点,它至多有左右两个子节点(可以为空),并且每个子树也都是二叉树。
如果无视有根二叉树中的父子关系,那么它就变成了无根树。现在我们给出任意的无根树,想让你找到这样的节点:存在某个有根二叉树的根为这个节点,且无视有根二叉树中的父子关系后,所变成的无根树恰好为给出的无根树。
由于有可能无解,也有可能有很多解,你需要对这些情况作出判断。
依题目所说,要构成二叉树,一个点连出去的边最多为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 |
} |