• ICPC 2019-2020 North-Western Russia Regional Contest


    A (codeforces.com)

    这题在移动不被挡板挡住以及不超过边界的情况下,每次走的越多那么次数就越少

    只要两个每次都走b-a步(已经是不被挡板挡住走的最多了),就不用考虑被挡板挡住的情况,只用单独考虑了,如果可以走b-a,就走b-a,不然就把剩下的走完,只要整除上取整即可

    AC代码:

    1. #include
    2. #define endl '\n'
    3. //#define int long long
    4. using namespace std;
    5. int a,b,n;
    6. void solve() {
    7. cin>>a>>b>>n;
    8. int d=b-a;
    9. int x=(n-b)/d+((n-b)%d!=0);
    10. int y=(n-a)/d+((n-a)%d!=0);
    11. cout<
    12. }
    13. int main() {
    14. ios::sync_with_stdio(false);
    15. cin.tie(0);
    16. cout.tie(0);
    17. int t=1;
    18. // cin>>t;
    19. while(t--) {
    20. solve();
    21. }
    22. return 0;
    23. }

    Problem - M - Codeforces

    这题就是问有几个三元组(i,j,k)满足a[j]是a[i]和a[k]的平均数

    做法是枚举j和k,然后看前面满足的i有几个

    unordered_map查找的平均时间复杂度是O(1),map查找的时间复杂度是O(logn)

    AC代码:

    1. #include
    2. #define endl '\n'
    3. //#define int long long
    4. using namespace std;
    5. const int N=1010;
    6. int a[N];
    7. int n;
    8. void solve() {
    9. cin>>n;
    10. unordered_map<int,int>mp;
    11. for(int i=1;i<=n;i++) cin>>a[i];
    12. int res=0;
    13. for(int j=1;j
    14. for(int k=j+1;k<=n;
    15. k++){
    16. res+=mp[2*a[j]-a[k]];
    17. }
    18. mp[a[j]]++;
    19. }
    20. cout<
    21. }
    22. int main() {
    23. ios::sync_with_stdio(false);
    24. cin.tie(0);
    25. cout.tie(0);
    26. int t=1;
    27. cin>>t;
    28. while(t--) {
    29. solve();
    30. }
    31. return 0;
    32. }

    Problem - I - Codeforces

    法一:该题对于每一个柱子,以该柱子为顶点作金字塔,根据几何关系,底面是确定的,然后求最小的能包含所有小底面的大底面,然后根据几何关系确定顶点,由于顶点要求x,y,z是整数,所以大底面边长得是偶数,所以如果是奇数,就得加1

    AC代码:

    1. #include
    2. #define endl '\n'
    3. #define int long long
    4. using namespace std;
    5. int n;
    6. void solve() {
    7. cin>>n;
    8. int x1=2e9,x2=-2e9,y1=2e9,y2=-2e9;
    9. for(int i=0;i
    10. int x,y,h;
    11. cin>>x>>y>>h;
    12. x1=min(x1,x-h);
    13. x2=max(x2,x+h);
    14. y1=min(y1,y-h);
    15. y2=max(y2,y+h);
    16. }
    17. int h=max((x2-x1)/2+((x2-x1)%2!=0),(y2-y1)/2+((y2-y1)%2!=0));
    18. cout<<(x1+x2)/2<<' '<<(y1+y2)/2<<' '<
    19. }
    20. signed main() {
    21. ios::sync_with_stdio(false);
    22. cin.tie(0);
    23. cout.tie(0);
    24. int t=1;
    25. // cin>>t;
    26. while(t--) {
    27. solve();
    28. }
    29. return 0;
    30. }

    法二:

     一共四个面,然后每个面的朝向以及斜率都是固定的,我们只需要考虑对于一根柱子,我们分别让四个面往柱子靠近,刚好能够抵住,这样合成的金字塔是覆盖所有柱子的情况下最小的

    就是刚好让柱子的顶点在这个面上,求出截距,然后取max(截距是在z轴上的截距)

    然后两两相邻的面可以与z=0这个面进行联立,得到底面4个交点坐标,从而确定整个底面,如果底面边长为奇数,那么加1(确保顶点坐标为整数),从而确定顶点坐标

    AC代码:

    1. #include
    2. #define endl '\n'
    3. #define int long long
    4. using namespace std;
    5. int n;
    6. struct Point{
    7. public:
    8. int x,y;
    9. Point(int x1,int y1):x(x1),y(y1){}
    10. };
    11. void solve() {
    12. cin>>n;
    13. int c1=-2e9,c2=-2e9,c3=-2e9,c4=-2e9;
    14. for(int i=0;i
    15. int x,y,h;
    16. cin>>x>>y>>h;
    17. //z=y+c1==>c1=z-y
    18. c1=max(c1,h-y);
    19. //z=x+c2==>c2=z-x
    20. c2=max(c2,h-x);
    21. //z=-y+c3==>c3=z+y
    22. c3=max(c3,h+y);
    23. //z=-x+c4==>c4=z+x
    24. c4=max(c4,h+x);
    25. }
    26. Point A(-c2,-c1),B(-c2,c3),C(c4,c3),D(c4,-c1);
    27. int h=max((D.x-A.x)/2+((D.x-A.x)%2!=0),(B.y-A.y)/2+((B.y-A.y)%2!=0));
    28. int x=(A.x+D.x)/2;
    29. int y=(C.y+D.y)/2;
    30. cout<' '<' '<
    31. }
    32. signed main() {
    33. ios::sync_with_stdio(false);
    34. cin.tie(0);
    35. cout.tie(0);
    36. int t=1;
    37. // cin>>t;
    38. while(t--) {
    39. solve();
    40. }
    41. return 0;
    42. }

    Problem - E - Codeforces

    法一:

    利用bfs一层一层搜,将加粗的所有点入队作为第一层,然后搜下一层,如果第一次搜到就更新距离加1,并且记录到该点为止一共有几个到它距离相同的加粗的点,把该点放入队列中,可以下一次继续拓展下一层,如果搜过了,那么看dist[u]是不是等于dist[v]+1,如果相等,那么可以把到点u距离相同的加粗的点的个数加到点v上

    最后枚举每个点,只要有一个点满足到该点的距离相同的加粗的点的个数为m,那么就输出YES,如果一个点也不满足,那么就输出NO

    AC代码:

    1. #include
    2. #define endl '\n'
    3. #define int long long
    4. using namespace std;
    5. const int N=2e5+10;
    6. int dist[N];
    7. int cnt[N];
    8. int n,m;
    9. vectorint>>e(N);
    10. void solve() {
    11. cin>>n>>m;
    12. for(int i=0;i-1;i++){
    13. int u,v;
    14. cin>>u>>v;
    15. e[u].push_back(v);
    16. e[v].push_back(u);
    17. }
    18. queue<int>q;
    19. for(int i=0;i
    20. int x;
    21. cin>>x;
    22. q.push(x);
    23. dist[x]=1;
    24. cnt[x]=1;
    25. }
    26. while(q.size()){
    27. int t=q.front();
    28. q.pop();
    29. for(auto v:e[t]){
    30. if(!dist[v]){
    31. dist[v]=dist[t]+1;
    32. cnt[v]+=cnt[t];
    33. q.push(v);
    34. }
    35. else if(dist[v]==dist[t]+1){
    36. cnt[v]+=cnt[t];
    37. }
    38. }
    39. }
    40. for(int i=1;i<=n;i++){
    41. if(cnt[i]==m){
    42. cout<<"YES"<
    43. cout<
    44. return;
    45. }
    46. }
    47. cout<<"NO"<
    48. }
    49. signed main() {
    50. ios::sync_with_stdio(false);
    51. cin.tie(0);
    52. cout.tie(0);
    53. int t=1;
    54. // cin>>t;
    55. while(t--) {
    56. solve();
    57. }
    58. return 0;
    59. }

    法二:

    利用树的中心(有专门的模板)

    先将那些不可能成为答案的点删掉(从叶子节点一直到加粗的点,将这些点标记,枚举到标记的点的时时候就跳过),这样所有叶子节点就都变成加粗的点了,然后求一遍树的中心,答案只可能在树的中心中(树的中心最多只有两个),因为树的中心到最远的点的距离最近,如果存在一个点满足到所有加粗的点(此时已经变成叶子节点了)的距离相等,那么它肯定是中心

    找到中心之后,进行验证是否是答案,只要跑一遍BFS,判断它到所有加粗的点的距离是否相等即可

    AC代码:

    1. #include
    2. #include
    3. #define endl '\n'
    4. #define int long long
    5. using namespace std;
    6. const int N = 2e5 + 10;
    7. int d1[N], d2[N];
    8. int p1[N];
    9. int up[N];
    10. int du[N];//度数
    11. int dist[N];
    12. bool vis[N];
    13. bool unused[N];
    14. bool teams[N];
    15. int n, m;
    16. vectorint>>e(N);
    17. vector<int>team;
    18. vector<int>zhongdian;
    19. int dfs_d(int u, int fa) {
    20. d1[u] = 0; //d1[u]记录从u点向下走的最大长度
    21. d2[u] = 0; //d2[u]记录从u点向下走的次大长度
    22. for (auto v : e[u]) {
    23. if (v == fa || unused[v]) continue; //避免向上搜索
    24. int d = dfs_d(v, u) + 1; //从u经ver点往下走的最大长度
    25. //p1[u]记录从u点向下走的最长路径是从哪个点下去的
    26. if (d >= d1[u]) d2[u] = d1[u], d1[u] = d, p1[u] = v;
    27. else if (d > d2[u]) d2[u] = d;
    28. }
    29. return d1[u];//返回从u点往下走的最大长度
    30. }
    31. void dfs_u(int u, int fa) {
    32. for (auto v : e[u]) {
    33. if (v == fa || unused[v]) continue; //避免向上搜索
    34. //up[ver]记录从ver点向上走的最大长度
    35. if (p1[u] == v) up[v] = max(up[u], d2[u]) + 1;
    36. else up[v] = max(up[u], d1[u]) + 1;
    37. dfs_u(v, u); //深搜u的子节点ver
    38. }
    39. }
    40. void solve() {
    41. cin >> n >> m;
    42. for (int i = 0; i < n - 1; i++) {
    43. int u, v;
    44. cin >> u >> v;
    45. e[u].push_back(v);
    46. e[v].push_back(u);
    47. //度数为1说明是叶子节点
    48. du[u]++;
    49. du[v]++;
    50. }
    51. for (int i = 0; i < m; i++) {
    52. int x;
    53. cin >> x;
    54. teams[x] = true; //标记一下teams里的点
    55. team.push_back(x);
    56. }
    57. //把那些没用的点都删掉,使得teams里的点全部成为叶子节点
    58. queue<int>q;
    59. for (int i = 1; i <= n; i++) {
    60. if (du[i] == 1 && !teams[i]) q.push(i);
    61. }
    62. while (q.size()) {
    63. int t = q.front();
    64. q.pop();
    65. unused[t] = true;
    66. for (auto v : e[t]) {
    67. if (--du[v] == 1 && !teams[v]) q.push(v);
    68. }
    69. }
    70. int start;//寻找起点,找一个没有被删除的点
    71. for (int i = 1; i <= n; i++) {
    72. if (!unused[i]) {
    73. start = i;
    74. break;
    75. }
    76. }
    77. //寻找中点
    78. dfs_d(start, -1);
    79. dfs_u(start, -1);
    80. int res = 2e9;
    81. for (int i = 1; i <= n; i++) {
    82. if (unused[i]) continue;
    83. res = min(res, max(d1[i], up[i]));
    84. }
    85. for (int i = 1; i <= n; i++) {
    86. if (unused[i]) continue;
    87. if (max(d1[i], up[i]) == res) zhongdian.push_back(i);
    88. }
    89. for (auto u : zhongdian) {
    90. for (int i = 1; i <= n; i ++) vis[i] = false;
    91. queue<int> q;
    92. q.push(u);
    93. dist[u] = 0;
    94. vis[u] = true;
    95. bool ok = true;
    96. while (q.size()) {
    97. int t = q.front();
    98. q.pop();
    99. for (auto v : e[t]) {
    100. if (vis[v] || unused[v]) continue;
    101. vis[v] = true;
    102. q.push(v);
    103. dist[v] = dist[t] + 1;
    104. }
    105. }
    106. for (int i = 1; i < (int)team.size(); i ++)
    107. if (dist[team[i - 1]] != dist[team[i]]) {
    108. ok = false;
    109. break;
    110. }
    111. if (ok) {
    112. cout << "YES" << endl;
    113. cout << u << endl;
    114. return;
    115. }
    116. }
    117. cout << "NO" << endl;
    118. }
    119. signed main() {
    120. ios::sync_with_stdio(false);
    121. cin.tie(0);
    122. cout.tie(0);
    123. int t = 1;
    124. // cin>>t;
    125. while (t--) {
    126. solve();
    127. }
    128. return 0;
    129. }
  • 相关阅读:
    无人值守的好帮手| 周界雷视声光报警柱工勘配置指导
    daml和xaml
    MySQL事务(Transaction)
    [PHP]得推跑腿O2O系统 v3.41
    剑指 Offer II 118. 多余的边-记忆搜索深度优先遍历
    实践分享!GitLab CI/CD 快速入门
    程序员有必要考个 985 非全日制研究生嘛?
    16.偏差、方差、正则化、学习曲线对模型的影响
    C++岗位方向暴力穷举法
    Hexagon_V65_Programmers_Reference_Manual(23)
  • 原文地址:https://blog.csdn.net/m0_74087709/article/details/133770520