文章目录

  • 考试心路历程
  • 联网
    • title
    • solution
    • code
  • 欧几里得
    • title
    • solution
    • code
  • 分解树
    • title
    • solution
    • code
  • 开关灯
    • title
    • solution
    • code

考试心路历程

佛了佛了,caocaocaocaocaocao 人直接炸嗨升天

并查集直接送走200200200分!!!我屮艸芔茻

T1二分检查直接离开——好家伙没想到没死在精度上,直接鞭尸并查集

之前还嘲笑香香mm,原来SB竟是我自己

T2构造不出来,拿了基础的部分分

T3并查集反着做,排序方法错了,不说了不说了,懂的都懂

T4敲了链的部分分但是没过,谁知道呢??

害!

总之这一场发挥非常离谱,从来没有这么炸过,可以说,题目又不难

联网

title

题目描述

有n个无线电信号站,每个无线电发射站的发射半径都必须相等,你可以统一设置它们半径。发射半径越长,则花费越大。如果两个无线电发射站能覆盖同一个点,则它们能够联网。如果A与B能联网,B与C能联网,则A,C也能联网。现在告诉你这n个无线电发射站的坐标,你需要让它们连成一个网络,请问最小的发射半径是多少?

输入格式

第一行包含一个整数nnn,表示无线电信号站的数量。

接下来有n行,每行包含两个整数xi,yix_i,y_ixi​,yi​,表示发射站的坐标

输出格式

一个实数,表示最小发射半径,保留7位小数。

输入样例1

2
1 1
2 2

输出样例1

0.7071068

输入样例2

7
2 3
3 4
4 5
0 1
3 1
4 2
1 5

输出样例2

1.4142135

输入样例3

4
2020 20
20 2020
2020 2020
20 20

输出样例3

1000.0000000

solution

二分距离,暴力检查,用并查集判断是否联通

最后注意并查集不要打错了,不然骨灰挥洒

code

#include <cmath>
#include <cstdio>
#define eps 1e-7
#define maxn 1005
struct node {double x, y;
}net[maxn];
int n;
int f[maxn];void MakeSet() {for( int i = 1;i <= n;i ++ ) f[i] = i;
}int FindSet( int x ) {return x == f[x] ? x : f[x] = FindSet( f[x] );
}void UnionSet( int u, int v ) {int fu = FindSet( u ), fv = FindSet( v );f[fv] = fu;
}double dis( int i, int j ) {return sqrt( ( net[i].x - net[j].x ) * ( net[i].x - net[j].x ) + ( net[i].y - net[j].y ) * ( net[i].y - net[j].y ) );
}bool check( double x ) {MakeSet();for( int i = 1;i <= n;i ++ )for( int j = i + 1;j <= n;j ++ )if( dis( i, j ) <= x * 2 )UnionSet( i, j );for( int i = 1;i < n;i ++ )if( FindSet( i ) != FindSet( i + 1 ) ) return 0;return 1;
}int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%lf %lf", &net[i].x, &net[i].y );double l = 0, r = 1e9, ans;while( r - l > eps ) {double mid = ( l + r ) / 2;if( check( mid ) ) ans = mid, r = mid;else l = mid;}printf( "%.10f\n", ans );return 0;
}

欧几里得

title

我们知道辗转相除法,现在给一个类似与辗转相除的函数R(a,b)R(a,b)R(a,b),定义如下
R(a,b)={R(b,a)a<bR(a,b)=\{ R(b,a)a<b R(a,b)={R(b,a)a<b

给你两个整数g,hg,hg,h,请你找两个整数a,ba,ba,b,使得它们满足gcd⁡(a,b)=g,R(a,b)=h\gcd(a,b)=g,R(a,b)=hgcd(a,b)=g,R(a,b)=h

输入格式

第一行包含一个整数t(1≤t≤40)t(1\le t\le 40)t(1≤t≤40),表示测试数据的组数。

接下来有ttt行,每行包含两个正整数g,hg,hg,h

输出格式

包含ttt行,每行包含两个整数a,ba,ba,b,表示符合上述条件的整数。

保证答案不超过1e181e181e18,可以证明一定有解。

1≤g≤200000,2≤h≤2000001\le g\le 200000,2\le h\le 2000001≤g≤200000,2≤h≤200000

输入样例1

1
1 4

输出样例1

99 23

输入样例2

2
3 2
5 5

输出样例2

9 39
5 5

solution

最后的答案长相一定是R(h,1)R(h,1)R(h,1),也就是说之前的每一次一定满足min(a,b)≥hmin(a,b)\ge hmin(a,b)≥h

那么每次都至少会让max(a,b)max(a,b)max(a,b)缩成原来的1h\frac{1}{h}h1​

假设操作进行了kkk次,那么构造得a∈[hk,2∗hk)a∈[h^k,2*h^k)a∈[hk,2∗hk)

又满足是ggg的倍数

有b=g∗⌈hkg⌉,a=b∗h+gb=g*\lceil\frac{h^k}{g}\rceil,a=b*h+gb=g∗⌈ghk​⌉,a=b∗h+g

code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
int T, g, h;signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld", &g, &h );int b = h;while( b <= g ) b *= h;if( b % g ) b += g - ( b % g );int a = b * h + g;printf( "%lld %lld\n", a, b );}return 0;
}

分解树

title

题目描述

有一棵树,有nnn个顶点,每个节点都有权值,现在你要将每条边都断开,你可以选择断开的顺序,最终的代价可能是不同的。断开一条边的代价为该边连接的两个连通块中各取一个最大权值的顶点之和。请问最后将所有边都断开的最小代价是多少?n≤1e5n\le 1e5n≤1e5

输入格式

第一行包含一个整数nnn,表示有nnn个顶点。

第二行包含nnn个整数,表示顶点iii的权值

接下来有n−1n-1n−1行,每行两个整数a,ba,ba,b,表示点aaa与点bbb相连。

输出格式

一个整数,表示最小的代价

输入样例1

3
1 2 3
1 2
2 3

输出样例1

8

输入样例2

4
2 2 3 2
1 3
3 2
4 3

输出样例2

15

输入样例3

5
5 2 3 1 4
2 1
3 1
2 4
2 5

输出样例3

26

solution

法一:反其道而行

相当于是加边,构成一棵树,加边操作为两边连通块各自的最大值之和,求最小花费

显然,肯定是边花费越小越先加

边按照连接的两个连通块的最大值从小到大排序(PS:不是和从小到大)

因为两条边先后合并顺序不同,只会是最大值加的不同

法二:找结论

独立计算每个点会产生多少次贡献,显然是从最大点值的边开始断着走

断开一条边时,设该边的两个点为xi,yix_i,y_ixi​,yi​,设txi>tyit_{x_i}>t_{y_i}txi​​>tyi​​,则xix_ixi​会作为当前的最大点算一次贡献,而第二大点也会算一次贡献

所有点(除了全局最大点之外)都有且仅有一次机会成为第二最大点被算一次贡献

因为算了贡献一次后,他就是他所在连通块中的最大点了,永远不可能再成为第二最大点

所以最终的贡献为:∑i<n(max(txi,tyi))+∑i≤nti−maxi≤n(ti)\sum_{i<n}(max(t_{x_i},t_{y_i}))+\sum_{i \leq n}t_i-max_{i\leq n}(t_i)∑i<n​(max(txi​​,tyi​​))+∑i≤n​ti​−maxi≤n​(ti​)

code

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100005
#define int long long
struct node {int u, v, w;node(){}node( int U, int V, int W ) {u = U, v = V, w = W;}bool operator < ( node &t ) const {return w < t.w;}
};
vector < node > G;
int n, ans;
int val[maxn], f[maxn];void MakeSet() {for( int i = 1;i <= n;i ++ ) f[i] = i;
}int FindSet( int x ) {return x == f[x] ? x : f[x] = FindSet( f[x] );
}void UnionSet( int u, int v ) {u = FindSet( u ), v = FindSet( v );ans += val[u] + val[v];f[v] = u;val[u] = max( val[u], val[v] );
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &val[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G.push_back( node( u, v, max( val[u], val[v] ) ) );}sort( G.begin(), G.end() );MakeSet();for( int i = 0;i < G.size();i ++ )UnionSet( G[i].u, G[i].v );printf( "%lld\n", ans );return 0;
}

开关灯

title

题目描述

有nnn盏灯,组成了一棵树,一开始有些灯是开着的,有些灯是关着的。你可以从任一盏灯开始,沿着树上的路径游走,你经过的地方,灯都会改变状态。你可以重复经过某一盏灯,每经过它一次,它的状态都会发生改变。你的目标是要将所有灯都变成开的状态。请问,你的游走轨迹上的最少的灯数是多少?如果你重复经过一盏灯,则它要算多次。

输入格式

第一行一个整数nnn。 接下来是一个nnn位的01串,表示灯的开关状态,000表示关,111表示开。 再接下来有 行,每行两个整数a,ba,ba,b,表示aaa与bbb相连。

输出格式

一个整数,表示答案。

输入样例1

3
010
1 2
2 3

输出样例1

4

输入样例2

5
00000
1 2
2 3
2 4
3 5

输出样例2

7

输入样例3

5
00100
1 2
2 3
2 4
3 5

输出样例3

8

solution

题解

大部分注释在代码里

code

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 500005
vector < int > G[maxn];
int n;
char s[maxn];
bool g[maxn];
int t[3][2];
int f[maxn][3][2];void dfs( int u, int fa ) {g[u] = s[u] - '0';for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;else dfs( v, u ), g[u] &= g[v];}
}void solve( int u, int fa ) {//f(u,i,j):subtree_u has i=0/1/2 endpoints of the path. at the beginning u is j=0/1
//the minicost to make nodes of subtree_u all be 1(lights all open)f[u][0][0] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa || g[v] ) continue;else solve( v, u );//subtree_v are all lighted just continueint ss = s[v] - '0';for( int j = 0;j <= 2;j ++ )for( int k = 0;k <= 1;k ++ ) {/*endpoints both belong to u_subtreev_subtree all rightu_subtree all right(except u itself)one endpoint -> u(wrong->right)cost 1*/t[j][k] = f[u][j][k ^ 1] + f[v][0][ss] + 1;/*endpoints both belong to u_subtreev_subtree all right(except v itself)u_subtree all rightone endpoint -> u(right->wrong) -> v(wrong->right) -> u(wrong->right)cost 3*/t[j][k] = min( t[j][k], f[u][j][k] + f[v][0][ss ^ 1] + 3 );if( j > 0 ) {/*one endpoint belongs to v_subtreethe other belongs to u_subtree or other subtrees(don't include u_subtree)v_subtree and u_subtree all rightjust f(u) plus f(v)*/t[j][k] = min( t[j][k], f[u][j - 1][k] + f[v][1][ss] );/*one endpoint belongs to v_subtreethe other belongs to u_subtree or other subtrees(don't include u_subtree)v_subtree and u_subtree all right(except u and v)we need to touch u and vcost another 2*/t[j][k] = min( t[j][k], f[u][j - 1][k ^ 1] + f[v][1][ss ^ 1] + 2 );}if( j > 1 ) {/*endpoints both belong to v_subtreev_subtree all right(except v itself)u_subtree all rightwe need tp touch vone endpoint -> v(wrong->right)cost 1*/t[j][k] = min( t[j][k], f[u][j - 2][k] + f[v][2][ss ^ 1] + 1 );/*endpoints both belong to v_subtreev_subtree all rightu_subtree all right(except u itself)one endpoint -> v(right->wrong) -> u(wrong->right) -> v(wrong->right)cost 3*/t[j][k] = min( t[j][k], f[u][j - 2][k ^ 1] + f[v][2][ss] + 3 );}}for( int j = 0;j <= 2;j ++ )for( int k = 0;k <= 1;k ++ )f[u][j][k] = t[j][k];}for( int j = 1;j <= 2;j ++ )for( int k = 0;k <= 1;k ++ )f[u][j][k] = min( f[u][j][k], f[u][j - 1][k] );//comparison choose a smaller one
}int main() {scanf( "%d %s", &n, s + 1 );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u ); }int rt = -1;for( int i = 1;i <= n;i ++ )if( s[i] == '0' ) {rt = i;break;} else;if( ~ rt ) {dfs( rt, 0 );printf( "NONO\n" );memset( f, 0x3f, sizeof( f ) );solve( rt, 0 );printf( "%d\n", f[rt][2][0] );}else printf( "0\n" );return 0;
}

[2021-06-19] 提高组新手副本Ⅱ(联网,欧几里得,分解树,开关灯)相关推荐

  1. LeetCode每日一题-2021/06/15-山脉数组的峰顶索引

    山脉数组的封顶索引–java–二分法 思路: 这道题最容易想到的就是枚举每个数字,而要想将时间复杂度降为O(logN), 可以使用二分的思想(利用arr[0] < arr[1] < - a ...

  2. P7470 [NOI Online 2021 提高组] 岛屿探险

    题目链接:P7470 [NOI Online 2021 提高组] 岛屿探险 以前都没有真正把cdqcdqcdq搞懂过,趁这次比赛花时间学了一下 SolutionSolutionSolution 对于m ...

  3. 2021牛客OI赛前集训营-提高组(第四场) T2空间跳跃

    2021牛客OI赛前集训营-提高组(第四场) 题目大意 给你三个整数 n , d , l n,d,l n,d,l, n n n为正整数.负整数或0, d , l d,l d,l为正整数,你现在有一个数 ...

  4. 信息学奥赛一本通 1407:笨小猴 | 1851:【08NOIP提高组】笨小猴 | OpenJudge NOI 1.9 06 | 洛谷 P1125 [NOIP2008 提高组] 笨小猴

    [题目链接] ybt 1407:笨小猴 ybt 1851:[08NOIP提高组]笨小猴 OpenJudge NOI 1.9 06:笨小猴 洛谷 P1125 [NOIP2008 提高组] 笨小猴 [题目 ...

  5. NOIP1998-2018 CSP-S2 2019 2021提高组解题报告与视频

    CSP-S 2020 讲题录屏 CSP-S 2020 讲题录屏_哔哩哔哩_bilibili 冠军说题--ACM世界冠军吴卓杰,带你复盘2020 CSP-S2 冠军说题--ACM世界冠军吴卓杰,带你复盘 ...

  6. Doris Weekly FAQ】2021.07.19~2021.08.01

    观众朋友们: 晚上好! 欢迎收看[ Doris 近日要闻]~本次为您带来的是 2021年07月19日 - 2021年08月01日 的双周总结. Doris 社区周报每期会包含 FAQ 环节.我们会在社 ...

  7. 提高组CSP-S初赛模拟试题整理

    目录 提高组 CSP−SCSP-SCSP−S 第 666 套初赛模拟试题整理 提高组 CSP−SCSP-SCSP−S 第 777 套初赛模拟试题整理 提高组 CSP−SCSP-SCSP−S 第 888 ...

  8. BZOJ刷题记录---提高组难度

    BZOJ刷题记录---提高组难度 总目录详见https://blog.csdn.net/mrcrack/article/details/90228694 序号 题号 算法 思想难度 实现难度 总难度 ...

  9. [NOIP2006] 提高组 洛谷P1066 2^k进制数

    题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后 ...

最新文章

  1. 如何在Bash中比较字符串
  2. 5.MySQL Cluster(MySQL集群)
  3. 开发腾讯移动游戏平台SDK ios版Ane扩展 总结
  4. Android Lifecycle源码解析(一)
  5. Educational Codeforces Round 94 (Rated for Div. 2)
  6. 一张有趣的图--《teach yourself c++ in 21 days》
  7. iptables的SNAT和DNAT应用
  8. 微服务应用实现无损上下线实践
  9. 洛谷P1321题题解(Java语言描述)
  10. 吴裕雄--天生自然 高等数学学习:两类曲线积分之间的联系
  11. macos 升级后 从前的 apachectl 错误, php 错误
  12. 【Matlab图像加密】Logistic+Tent+Kent+Henon图像加密与解密【含GUI源码 1745期】
  13. 微服务架构开发实战:什么是微服务的熔断机制和熔断的意义
  14. html设置可编辑状态,HTML5 - 使某个页面元素或整个页面可编辑
  15. 网络安全学习记录-10
  16. 软件测试质量度量,软件测试过程质量的度量
  17. 带动画效果的下拉菜单
  18. Linux上安装和卸载Redis实例教程
  19. 关于自控力和拖延 的一点分享--《自控力》
  20. 【Reactjs】多层展示报表信息

热门文章

  1. 《自然》杂志:中国人越来越沉迷于对着一个叫“区块链”的东西胡言乱语
  2. 多个goruntine 性能变慢_提高 JavaScript 性能的 12 个技巧
  3. python turtle 绘图_谈一下Pycharm中关联系统Python解释器的方法
  4. python每天定时9点执行_python 定时器每天就执行一次的实现代码
  5. 金蝶凭证序时簿在哪_来了!金蝶日常账务处理大全
  6. mysql表空间权限_MySQL InnoDB表空间加密示例详解
  7. C++ 学习之旅(13)——枚举enum
  8. [Redis6]常用数据类型_String字符串
  9. Java StringBuffer 方法
  10. 《C++ Primer》7.5.1节练习