zoukankan      html  css  js  c++  java
  • Atcoder AGC001 解题报告

    (A. BBQ Easy)

    简要题意:

    (2N)个数字分成两个一组,每一组的价值是较小的数字,求总的价值最大的分组方案。

    题目解法:

    题目相当于将数字分成两组(A)(B),使得分别排序后,都是(A_i leq B_i),并且最大化(sum A_i)
    将原数组排序,设为({S_i}),那么有(S_1 in A)
    我们的目标是最大化(sum A_i),等价于最小化(sum B_i)
    那我们就可以用(S_1)(S_2)拼掉,也就是将(S_2)放在(B)中,这一定是最优的。
    此时问题规模就缩小了,就可以继续做了。
    所以说,答案就是排序之后奇数位的数字和。

    (B. Mysterious Light)

    简要题意:

    有一个边长是(N)的正三边形,从距离一个顶点(X(X<N))处,平行于一条直线射入三角形。
    与特殊的光线不同,这一束光可以被自己的轨迹反射(当然,也可以被三角形反射)。
    可以证明,这束光最终一定会回到出发点,求出这束光回到出发点之前经过的路径长度。

    题目解法:

    这道题,个人感觉就是肉眼观察题,如图:

    (忘了在图中标出长度和点了。。。将就一下吧。)
    通过图,我们发现,如果用第一条和第二条分割三角形,就可以得到一个平行四边形。
    而且光束一定是从其中一个大小是 (frac{2 pi}{3})的角射入,最终只有两种情况:

    1. 光束正好到达出发点(另一个 (frac{2 pi}{3}) 角),此时一定有:长边长度(a)是短边长度(b)的倍数。
    2. 否则,就可以转化成一个子问题:长边是(y),短边是(x mod y)
      那么我们就可以用类似欧几里德算法的递归方式求解了。

    (C. Shorten Diameter)

    简要题意:

    给定一个无根树,可以进行若干次如下操作,使得这棵树直径长度不超过(K)

    选择一个叶子,将其及其邻边删除。

    求最少进行多少次操作,能够达成目标。

    题目解法:

    最开始想的是重心一定不会删,于是以重心为根树形DP。。。
    事实证明我(naive)了,一是重心可能删,二是我的(DP)应该是(N^3)(N^2log{N})的。
    好吧,最终还是参考了其他人的解法:
    题目是最小化删点个树,也就是最大化留下的点的个树。
    于是分(K)是奇数还是偶数讨论:
    (1) (K equiv 0 (mod 2))
    此时,我们一定能找到一个点,剩下的点中距离这个点最远的点,距离不超过(frac{k}{2})
    (1) (K equiv 1 (mod 2))
    此时,我们一定能找到一条边,剩下的点中距离这条边最远的点,距离不超过 (frac{k-1}{2})
    这两种情况我们都能枚举枚举点或边,再(O(N))计算,总的就是(O(N^2))

    (D. Arrays and Palindrome)

    简要题意:

    原本有两个数组({ A })({ B }),满足以下性质:

    • (sum A = N), (sum B = N), (Ai, Bi in N_{+})
    • 只有每一个位置都相同的长度为(N)的数组,才满足这两个性质:

      (1):将这数组分段:开头(A_1)个数,再(A_2)个数,再(A_3)个数(dots)以此类推,使得每一段都是回文的。
      (2):将这数组分段:开头(B_1)个数,再(B_2)个数,再(B_3)个数(dots)以此类推,使得每一段都是回文的。

    但是现在,这两个数组都丢了,只知道(N)(M) (({ A })的长度) 以及将({ A })打乱之后的数组({ C })
    请构造一组原来的({A })({ B })

    题目解法:

    我们思考一下那个回文的限制:
    如果我们将每一组的回文对应位置(也就是一定相等的位置)连一条边,那么这(N)个点是在同一个联通块里的。
    我们思考一下这些边怎么来的,如果存在一个长度为(len)的区间回文限制,那么我们就能连(leftlfloorfrac{len}{2} ight floor)条边。
    众所周知,(N)个点要联通,最少要(N-1)条边。
    那么就可以得到,如果({ C })中有大于两个奇数,就无解了,这是因为每一个奇数段,都会空出一个点,如果有三个空出来的就会少两条边,连树都不能构成了。
    满足这个条件,我们就可以构造({ B })了,就是按照将每一段的中心错开,将每一条边错开的原则。
    具体的说:将({C})的奇数放在两端,就是({ A })了,再将(A_1-=1)(A_M+=1),就是({ B })了,代码真简单

    (E. BBQ Hard)

    简要题意:

    给出(N)个二元组((A_i,B_i)),求下面式子的值:

    [sum_{i=1}^{N-1} sum_{j=i+1}^{N} {A_i+B_i+A_j+B_j choose A_i+B_i} ]

    题目解法:

    我们回想一下(x+y choose x)的组合意义:从((0,0))((x,y))的路径条数。
    那么我们可以拓展到((x_1-x_0)+(y_1-y_0) choose (x_1-x_0))就是从((x_0,y_0))((x_1,y_1))的路径条数。
    可以发现,从((-x_0,-y_0))((x_1,y_1))的路径条数就是和题目一样的形式了。
    那么我们可以将题目先变形:

    [frac{ sum_{i=1}^{N} sum_{j=1}^{N} {A_i+B_i+A_j+B_j choose A_i+B_i} - sum_{i=1}^{N} {2A_i + 2B_i choose 2A_i} }{2} ]

    现在就只要考虑求出任意两个数之间的贡献了,这个经过上面的转化很好做:
    我们考虑一个(x in [-2000,2000], y in [-2000,2000])的直角坐标系,
    最开始,在所有的((-A_i,-B_i))上加一个一,之后DP,用组合数的递推就好了。

    (F. Wide Swap)

    简要题意:

    给定一个排列,每次操作可以交换差值为1并且距离大于(K)的两个数。
    求出能构造出来的字典序最小的排列。

    题目解法:

    因为距离大于(K)这个限制很恶心,考虑在这个排列的逆(也就是位置排列)上操作:
    那么每次就是选相邻的而且差值大于(K)的两个数交换,而且因为是逆,所以我们现在是要最大化字典序了。
    能够发现,如果两个数差值小于等于(K),那这两个数的相对位置一定不会改变。
    就相当于是前面的数向后面的数连一条边,之后的拓扑序就是一个合法的排列,也可以最大化字典序了。
    但是这样有(O(N^2))条边,不可行,考虑利用传递性去掉一些边,例如((x,y))((y,z))((x,z)),其中((x,z))没用。
    这样的话,我们就从后往前向后面的点连边,但是只需要连两条:这个数(pm K)的范围,正负各连一条到满足要求的最近的点(因为其他的合法的点一定会连到这两个点)。
    这个连边操作可以用线段树简单实现,之后就是跑一遍拓扑序的事儿了。

  • 相关阅读:
    mybatis的延时加载缓存机制
    mybatis03
    事务
    codeforces-200B
    codeforces-339B
    codeforces-492B
    codeforces-266B
    codeforces-110A
    codeforces-887B
    codeforces-69A
  • 原文地址:https://www.cnblogs.com/tacmon52818/p/12709018.html
Copyright © 2011-2022 走看看