二叉树的根 CH Round #49 - Streaming #4 (NOIP模拟赛Day2)
描述
什么叫二叉树?这个应该是每个人都知道的。在本题中,我们的二叉树是有根的:对于每个节点,它至多有左右两个子节点(可以为空),并且每个子树也都是二叉树。
如果无视有根二叉树中的父子关系,那么它就变成了无根树。现在我们给出任意的无根树,想让你找到这样的节点:存在某个有根二叉树的根为这个节点,且无视有根二叉树中的父子关系后,所变成的无根树恰好为给出的无根树。
由于有可能无解,也有可能有很多解,你需要对这些情况作出判断。
输入格式
第一行为一个正整数n,代表树中点的个数。
接下来n-1行,每行一对非负整数a[i],b[i],表示a[i]与b[i]之间连有一条边。
输出格式
第一行为一个非负整数,表示解的数量。
如果解的数量不为0,那么第二行有若干正整数,每个表示一个答案,且按升序排列。
样例输入
输入1: 3 1 2 2 3 输入2: 4 1 2 1 3 1 4
样例输出
输出1: 3 1 2 3 输出2: 3 2 3 4
数据范围与约定
对于20%的数据,n≤3。
对于40%的数据,n≤4。
对于60%的数据,n≤100。
对于80%的数据,n≤1,000。
对于100%的数据,n≤100,000。
样例解释
对于第一个样例,任意一个节点都可以成为根,使得树成为二叉树。
对于第二个样例,如果以节点1为根,那么它就会有3个子节点,破坏了二叉树性质。而对于其余节点都是可行的。
Solution : 稍微思考一下可以发现,如果无根树中存在出度和入度之和大于3的点的话,那么整一个无根树无论取谁为根都是是无法满足题目要求的,而满足要求的点则满足出度和入度之和小于3。
距离统计 CH Round #49 - Streaming #4 (NOIP模拟赛Day2)
描述
现在有一个n×m的点阵,以这些点为顶点可以组成很多条线段。
有T次询问,每次询问给出l,求这些线段中长度为l的个数。
输入格式
第一行为三个正整数n,m,T,分别代表点阵的长和宽,以及询问的次数。
第二行为T个正整数,每个表示一个l。
输出格式
一行T个正整数,每个表示一个答案。
样例输入
输入1: 3 3 3 1 2 3 输入2: 4 5 1 5
样例输出
输出1: 12 6 0 输出2: 2
数据范围与约定
对于20%的数据,n,m≤20,T≤10。
对于40%的数据,n,m≤1,000,T≤100。
对于60%的数据,n,m≤100,000。
对于100%的数据,n,m≤1,000,000,000,T≤1,000,l是在[1,2max(n,m)]内随机生成的。
样例解释
对于第一个样例,长度为1的线段有12条(横竖各6条),长度为2的线段有6条(横竖各3条),没有长度为3的线段。
对于第二个样例,长度为5的线段只有2条对角线。
Solution : 因为问题的主要是要求a^2 + b^2 = l^2,我们有一个结论,如果x^2 + y^2 = z^2 && gcd(x,y,z) == 1那么z-x是一个完全平方数,或者一个完全平方数的两倍。于是我们可以通过枚举l的约数,使得问题得到转化。
#include<cstdio>
#include<cmath>
#define Push 0.1
#define lim 50000
#define ll long long
using namespace std;
bool prime[lim+10];
int num[lim],tot,ask[1100],how,l,a[lim],x[lim];
long long n,m,t,ans;
void init(){
scanf("%lld%lld%lld",&n,&m,&t);
for (int i = 1;i <= t;i ++) scanf("%d",&ask[i]);
}
void Select_Prime(){
for (int i = 2;i <= lim;i ++) if (! prime[i]){
num[++tot] = i;
for (int j = i*2;j <= lim;j += i) prime[i] = true;
}
}
void calc(int l){
how = 0;
for (int i = 1;i <= tot;i ++){
if (num[i] * num[i] > l) break;
if (l % num[i] == 0){
x[++ how] = num[i];
a[how] = 0;
while (l % num[i] == 0){
l /= num[i];
a[how] ++;
}
}
}
if (l > 1){
x[++ how] = l;
a[how] = 1;
}
}
long long gcd(long long a,long long b){
long long c;
while (b){
c = a % b; a = b;b = c;
}
return a;
}
void Plus(long long a,long long b){
if (n > a && m > b) ans += (n-a)*(m-b)*2;
if (m > a && n > b) ans += (m-a)*(n-b)*2;
}
void check(int x){
for (int dd = 1;dd <= 2;dd ++){
for (int i = 1;i <= x;i ++){
long long b = x - i*i*dd;
if (b <= 0) break;
long long gue = (ll)x*(ll)x-b*b;
double g = sqrt(gue);
if (g >= b) break;
long long a = g + Push;
if (a*a == gue && gcd(x,gcd(a,b)) == 1) Plus(a*(l/x),b*(l/x));
}
}
}
void inumerate(int wh,long long sum){
if (wh > how) check(sum);else
for (int i = 1;i <= a[wh]+1;i ++){
inumerate(wh+1,sum);
sum *= x[wh];
}
}
void work(){
Select_Prime();
for (int i = 1;i <= t;i ++){
l = ask[i];
ans = 0;
if (l < m) ans += (m-l) * n;
if (l < n) ans += (n-l) * m;
calc(l);
inumerate(1,1);
printf("%lld ",ans);
}
}
int main(){
init();
work();
}电阻网络 CH Round #49 - Streaming #4 (NOIP模拟赛Day2)
描述
什么是电阻?这个大家应该都知道。什么是电路?大家也应该知道。但是本题当中,电路的定义或许有点不同:
电路都带有正、负极接点,正极在左,负极在右。具体地:电路分为以下几类:
单独的一个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'为负极。
现在给出一个电路,求它正负极之间的电阻。
输入格式
第一行为两个正整数n,m,分别代表接点数和电阻数。保证编号小的接点在编号大的接点的左侧。
接下来m行,每行三个整数a[i],b[i],c[i],代表这个电阻连接了a[i]与b[i]接点,其阻值为c[i],其中c[i]只可能是0或1,且对于任意的i,保证a[i]<b[i]。
输出格式
输出一个实数,表示总的电阻值,保留三位小数输出。
样例输入
7 7 1 2 0 1 3 0 2 4 1 3 5 1 4 6 0 5 6 0 6 7 1
样例输出
1.500
数据范围与约定
对于20%的数据,n≤5。
对于50%的数据,n≤100。
对于70%的数据,n≤1,000。
对于100%的数据,n≤100,000,数据是在人工指定的$n$下随机生成的,保证答案不会超过10.000。
样例解释
画出图来,答案是显然的。
Solution : 这其实只是一道模拟题,考的是题目阅读能力(大雾),对于一个电路,我们从1号接线柱开始搜索,用vector记录一个点的出路,如果是并联的电路就当作两个串联处理,只是最后要用并联的公式处理答案而已,这样一直搜索到最后一个接线柱就可以得出答案了。
#include<cstdio>
#include<vector>
#define maxn 100100
using namespace std;
double ans;
std::vector<int> son[maxn];
int n,m,u,v,x,t,resi[maxn];
void init(){
scanf("%d%d",&n,&m);
for (int i = 1;i <= m;i ++){
scanf("%d%d%d",&u,&v,&x);
son[u].push_back(v);
resi[u] = x;
}
}
double dfs(int x,int &t){
if (x == n) return 0;
if (resi[x] == 0){
if (son[x].size() == 1){
t = son[x][0];
return 0;
} else {
double a = dfs(son[x][0],t);
double b = dfs(son[x][1],t);
return a*b/(a+b) + dfs(t,t);
}
} else return dfs(son[x][0],t)+1;
}
int main(){
init();
ans = dfs(1,t);
printf("%.3lf",ans);
}

该博客主要介绍了NOIP模拟赛Day2中的三个问题:如何在无根树中寻找符合条件的二叉树根,距离统计问题的解决策略,以及电阻网络的电路电阻计算方法。通过对样例的分析,阐述了解题思路和数据范围约束。
2650

被折叠的 条评论
为什么被折叠?



