zoukankan      html  css  js  c++  java
  • ATcoder Grand Contest总结

    最前面:

    AT的题都很有思维难度,总结一下一些AT的常规操作

    1.对于有操作的题目,如果正面推不行的话考虑倒推,将操作转化,寻找更好的性质

    2.模型转化,看到某一种的计算的式子,需要考虑有没有更简化的模型可以达到相同的效果

    3.补集转化,正难则反

    4.分析题目性质,计数题要找到一些限制条件或者构造方案使得计数不重不漏

    目标:稳定三题

    比例:D:0/1  C:3/6 B:2/3

    AGC37C Numbers on a Circle

    首先AT常规操作,考虑倒推。那么现在题目就变为

    1.选择一个下标i,将$b_{i}$减去左右两边的数

    2.题目的目标变为从$b$数组变为$a$数组

    由于$a,b$都是正整数,在任意一次操作之后,不能使$b$中的数变为负数,那么$b_{i}>b_{i-1}+b_{i+1}$,然后由于$b$中的值只会减小不会增加,所以$b_{i}>a_{i}$

    现在考虑如果i满足上述条件,那么$b_{i}>b_{i-1},b_{i}>b_{i+1}$,对于$i-1,i+1$上述条件一定不满足(第一个条件),所以必须先对i进行操作,才能对左右两个下标进行操作,那么其实操作的大体顺序已经定下来了。相当于每三个分一个组,先把满足条件的数放到队列里,对其进行操作之后再判断一下旁边的两个数是否可以进行操作,如果可以就将点加入队列中。

    看到官方题解和网上很多题解都是将所有的数都扔到一个堆里每次取出最大的数进行操作,其实并不需要这个堆,因为中间那个数不进行操作的话,左右两边的数一定不会满足条件,其实每一轮操作的顺序都是环上每隔三个数有一个数进行操作,由于每个数互不影响,所以操作顺序不会影响操作数量

    复杂度$O(nlogMAX)$

    代码

    AGC37B RGB Balls

    首先要考虑如何构造出一组最优的合法方案。考虑将每种球分组后以下标排序,然后将相同下标的三种球放在一起进行考虑

    $a_1<a_2<a_3<...<a_{n-1}<a_n$

    $b_1<b_2<b_3<...<b_{n-1}<b_n$

    $c_1<c_2<c_3<...<c_{n-1}<c_n$

    也就是将三种球的下标记录在$a$,$b$,$c$三个数组中,最终最优方案的答案就是$sum_{i=1}^{n} max{a_i,b_i,c_i}-min{a_i,b_i,c_i}$

    记$A$为$max{a_i,b_i,c_i}$组成的集合,$C$为$min{a_i,b_i,c_i}$,$B$为除$A,C$集合中其他的位置

    可以发现$A$中所有元素都是对计算的值产生正的贡献,$C$中所有元素都是对计算的值产生负的贡献,$B$对计算的值无贡献

    那么只要使最终的分配方案能使产生贡献的球都是$A,C$集合中的值即可

    那么对于一个人,只要满足选到的球先是$C$集合中的,再是$B$集合中的,最后是$A$集合中的

    从左往右枚举球,中途记录一下当前该选哪个集合的人有多少个,每次对答案乘上人数即可

    代码

    AGC39C Division by Two with Something

    首先要将题目转化一下,对于一个二进制数,对其进行操作就是将最后一位取反放到前面,然后删掉最后一位

    可以将这个二进制下的数取反复制到原数的前面,那么一个循环中的数可以通过截取所有得到的新数中长度为$n$的子串得到

    考虑一个循环是怎么形成的,一个数通过$2n$次操作一定会变回原来的数,相当于前$n$次操作对原来的数进行了取反,后面$n$次操作对已经取反的数再进行一次取反,两次取反就会得到原来的串

    再考虑循环在字符串上的意义,一个最短的循环就是拼接起来得到的那个字符串的最小循环节长度

    设循环的次数为i,因为通过$2n$次操作一定回到原数,$n$次操作得到取反后的串,那么$imid 2n$,$i mid n$

    循环节内部是有一个串和它的反串拼起来的

    枚举$2n$的因子$i$,统计对于存在循环节为i的串的个数,注意是循环节不是最小循环节(最后容斥回去即可)

    如果前$i/2$位比$x$的前$i/2$位小,那么之后循环的时候一定在$x$以内

    那么只要判断一下前$i/2$位等于$x$的前$i/2$位,然后构造出前$n$个,比较与$x$的大小,如果比$x$小就对统计的个数$+1$即可

    但不过此时统计的数量并不是最小循环节的数量,一个循环节会在循环节长度的倍数处重复统计,最后枚举其倍数容斥即可

    代码

    AGC36C GP 2

    窝连最开始的限制条件都没想到

    考虑最终的序列要满足什么条件才能被表示出来。很明显有$sum_{i=1}^{n} x[i]=3m$,然后考虑一个数最大只能是$m$个$2$加起来,那么$max_{i} x[i]leqslant 2m$,由于是一个$+1$另一个$+2$,那么每一次最多改变一个数的奇偶性,那么$sum_{i=1}^{n} [x[i]\%2=1]leqslant m$

    可以发现操作集合到满足这个限制条件序列的集合是一个满射,这种统计方案不重不漏

    只考虑第一个和第三个限制条件,不考虑第二个,那么可以先在序列上若干个$1$,然后再在序列上放$2$,那么可以枚举放1的数量

    $sum_{i=0,(3m-i)\%2=0}^{m}C_{n}^{i}C_{n+frac{3m-i}{2}-1}^{n-1}$

    再考虑第二个限制条件,可以发现如果第二条件不满足,那么只有$1$个数不满足限制,那么考虑补集转化

    枚举那个不满足的数有多大,再将剩下的数分配到$n-1$个位置里

    再考虑一下第三个限制条件,可以发现,如果一个数大于$2m$,那么序列上不为$0$的数最多有$m$个数,即使全部都为奇数,也符合第三个限制条件,所以不用再考虑第三个限制条件

    $nsum_{i=2m+1}^{3m}C_{n+3m-i-2}^{n-2}$

    两式相减即为答案

    代码

    AGC34C Tests

    可以发现,如果一门考试比另外一个人高了,那么重要度一定要设为$u_i$,并且要学到满分,因为每一门考试都有一个$b_i$,只有超过$b_i$才能反超另外一个人,那么有一门考试已经超过$b_i$,那就要充分利用这门考试,去学其他的考试一定没有比把这个考试学到满分优(因为还要先学到$b_i$才可以);如果一门考试比另外一个人低,那么重要度一定要设为$l_i$

    那么在这种策略之下,最多只有一门考试学习过但没有学到满分,其他的考试要么没有学要么已经学到了满分,原因是可能有边角料的存在,会使得有一门课不是满分

    因为一开始每一门考试都是$0$分,那么与另一个人的差距就是$tot=sum_{i=1}^{n} b_il_i$,如果把第i门课学到满分可以缩小的差距就是$v_i=(x-b_i)u_i+b_il_i$,那么以$v$从大到小排序,贪心的选择能缩小差距最大的那门考试,将初始的差距减去$v_i$

    那么就是以$v$从大到小排序之后,找到最大的$k$,使得$sum_{i=1}^{n}v_ileqslant tot$

    但是因为不一定能把初始差距减到$0$,那么就需要有一门考试来处理这个边角料,考虑枚举这个考试,分两种情况讨论

    如果当前枚举的考试在前$k$个中,那么将当前枚举到考试替换成第$k+1$个考试满分,然后判断计算当前这个考试需要的时间

    如果不在,直接计算即可

    考虑如何计算一个考试需要花费的时间,如果边角料少于$b_il_i$那么重要度设为$l_i$,否则就设为$u_i$

    我看到网上和官方题解都是带了一个二分时间,其实并不需要

    还有我一开始写的程序被corner case卡WA了,需要特判所有$b_i$都是$x$的情况

    代码

    AGC47C Product Modulo

    这种题AT很少见啊

    看到这个式子会发现一般的处理方法很难进行处理,我比赛的时候打了一个整除分块,时间复杂度也假了。但可以发现这个模数给的很特殊,不是一般的$998244353$和$1e9+7$,那么从质数的性质出发

    可以发现如果式子里不是乘法而是加法,那么是很好计算的,可以使用FFT或者其他的技巧计算,考虑如何把乘法变换为加法,很明显对乘数取一个$log$就可以化乘为加,那么考虑底数的选取

    质数的原根$g$,保证在$1leq i< p-1$,$g^{i}$两两不同,那么考虑用$g$作为底数,由于$p$不大,直接枚举次数,将每一个数取对数,然后用FFT加速加法运算(在每个数对应次数的位置$+1$,将这个多项式自乘$1$次)

    代码

    AGC47D Twin Binary Trees

    一个由i,j两个叶子节点组成的简单环是i到j在树上的路径和p[i]到p[j]树上的路径组合起来的,如果记录一下每一个叶子节点到根路径上节点标号的乘积$fac$,那么i到j的路径上的节点标号乘积就是$frac{fac_ifac_j}{LCAfac[father_{LCA}]}$

    考虑枚举每一个LCA,分别来自每一个节点左右子树的叶子节点组成的路径的LCA是当前节点,那么在第一棵树上的乘积很好计算,直接枚举左右子树的叶子节点。对于第二棵树,考虑先遍历左子树,对于叶子节点$i$,在$p[i]$到根节点的路径上每一个节点都打上标记,标记上记录通过这个点的所有路径的乘积之和,这里的乘积要乘上第一棵树的贡献,枚举右子树的所有叶子节点,也在第二棵树的上遍历,遍历到的点记录的权值减掉上一次遍历到的点乘上当前标号,就是左子树的叶子节点和这个节点LCA的乘积之和,累计答案即可

    代码

  • 相关阅读:
    .Net关闭数据库连接时判断ConnectionState为Open还是Closed?
    Excel里生成GUID
    Convert.ChangeType不能处理Nullable类型的解决办法
    xml编辑无提示?这么破!
    如何往eclipse中导入maven项目
    巧用浏览器F12调试器定位系统前后端bug
    Web自动化selenium技术快速实现爬虫
    Git一分钟系列--快速安装git客户端
    web自动化原理揭秘
    Web自动化测试环境搭建1(基于firefox火狐浏览器)
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/13435496.html
Copyright © 2011-2022 走看看