CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

来源:互联网 发布:炭知天下龙泽路手机号 编辑:程序博客网 时间:2024/05/01 05:40

二叉树的根 CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

描述

什么叫二叉树?这个应该是每个人都知道的。在本题中,我们的二叉树是有根的:对于每个节点,它至多有左右两个子节点(可以为空),并且每个子树也都是二叉树。

如果无视有根二叉树中的父子关系,那么它就变成了无根树。现在我们给出任意的无根树,想让你找到这样的节点:存在某个有根二叉树的根为这个节点,且无视有根二叉树中的父子关系后,所变成的无根树恰好为给出的无根树。

由于有可能无解,也有可能有很多解,你需要对这些情况作出判断。

输入格式

第一行为一个正整数n,代表树中点的个数。

接下来n-1行,每行一对非负整数a[i],b[i],表示a[i]与b[i]之间连有一条边。

 

输出格式

第一行为一个非负整数,表示解的数量。

如果解的数量不为0,那么第二行有若干正整数,每个表示一个答案,且按升序排列。

样例输入

输入1:31 22 3输入2:41 21 31 4

样例输出

输出1:31 2 3输出2:32 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 31 2 3输入2:4 5 15

样例输出

输出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 longusing 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);elsefor (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 71 2 01 3 02 4 13 5 14 6 05 6 06 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 100100using 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);}


后记:这场比赛其实真正说没想到的只有第二题,但是当时看完题目后认为第二题会比第三题更加好写,于是就先做第二题,花了一个小时之后,越陷越深,到最后还是没有想出正解,结果白白浪费了第三题,以后对于一些题目意思较难明白的题目不要认为就是难做,很可能是道水题,而对于已经开始想的题,如果没有十分充足的把握,就应该先放一边。

0 0
原创粉丝点击