• 连飞学长的爱 解题报告 Apare_xzc


    连飞学长的爱 解题报告

    2019/2/22

    vj链接


    A-A
    CodeForces - 560A
    题意
    有一套纸币,有n个币种,问是否能构成任意面值?
    input:
    n
    a1 a2 … an
    数据范围:
    n<=1000 ai<=1e6

    思路:
    只要判断币种面值有没有1即可


    B-B
    CodeForces - 560B
    题意:
    有两张矩形的画,和一个矩形的墙,问墙上是否能放下两张画?
    input:
    a1 b1(墙的长、宽)
    a2 b2(第一张画的长、宽)
    a3 b3(第二张华的长、宽)
    数据范围:
    ai,bi<=1000

    思路:
    四种拼接方式,一种满足即可

    bool solve()
    {
        int x = a2+a3;
        int y = max(b2,b3);
        if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
        x = a2+b3;
        y = max(b2,a3);
        if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
        x = b2+a3;
        y = max(a2,b3);
        if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
        x = b2+b3;
        y = max(a2,a3);
        if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
        return false;
    }
    

    C-C
    CodeForces - 559B
    题意:
    两个字符串满足下列两个条件之一输出yes:
    (1) A[1,2…lena] == B[1,2…lenb]
    (2) 把A分成前后长度相等的两部分a1+a2 B分成b1+b2,满足
    (a1=b1且a2=b2) 或 (a1=b2且a2=b1)
    输入:
    (字符串)A
    (字符串)B
    数据范围
    length <= 200 000

    思路:
    递归判断即可
    拿到两个字符串A,B

    • 先判断A,B是否相等 若相等,return true;
    • else if len为奇数,return false;
    • else return (a1=b1且a2=b2) 或 (a1=b2且a2=b1)
    • 这里可以剪枝:如果字符串A,B中相同字母出现的次数不同,直接return false;
      我的代码<-戳这里

    D-D
    CodeForces - 559C
    题意: 小学奥数题升级版->走网格
    网各为h*w (h,w<=1e5)
    有n个格子是黑色的,其余是白色的(n<=2000)
    从左上角走到右下角,每次只能向下或向右走1格(不能走到格子外面)
    其中黑色的格子不能走,问从左上角到右下角的方案数,答案对1e9+7取模
    数据范围
    1<=h,w<=1e5
    1<=n<=2000
    mod = 1000 000 007
    思路:

    • 这道题,小学奥数的做法是一行一行的递推
      因为只能向下走或向右走,所以从起始走到格子(i,j)的方案数dp[i][j] = dp[i-1][j] + dp[i][j-1] (dp[1][1]==1)
      遇到黑色的格子,直接dp[i][j] = 0;

    • 如果没有黑色的格子,从起始位置(1,1)走到格子(i,j)的方案数就是C(i+j-2,i)。因为从(1,1)到(i,j)总距离为垂直距离i-1加上水平距离j-1,令tot = i-1+j-1,只是在tot步中选择i-1步往下走
      C(n,m)代表组合数

    • 为了叙述方便我们先写一个函数Dis(x0,y0,x1,y1)
      其中x1>=x0, y1>=y0 这个函数表示从点(x0,y0)走到点(x1,y1)的方案数
      则Dis(x0,y0,x1,y1) = C(x1-x0+y0-y1,x1-x0)

    • 因为黑色格子的个数n比较少,我们可以从黑色格子入手
      如果一个格子(i,j)的左上方没有其它的黑色格子,则起始点到它的走法为Dis(1,1,i,j)
      如果一个格子(i,j)的左上方有黑色格子(a,b)那么不能由P走到当前的格子,所以要减去(a,b)到(i,j)的方案数
      假设起始格子到(a,b)的方案数dp(a,b)已知,则要减去的数为:dp(a,b) * Dis(a,b,i,j)

    • 所以,从起始格子走到右下角的方案数就是Dis(1,1,h,w)减去所有在它左上方的黑色格子(a,b)对它的影响:dp(a,b)*dis(a,b,h,w) 而计算起点到黑色格子(a,b)的方案数又要用(a,b)左上方的黑色格子的方案
      所以把所有的黑色格子按先x后y排序,一次求出dp(xi,yi)即可
      这里我们可以O(n)预处理出2e5以内的所有阶乘和阶乘的逆元

    int N = 2e5;
    int mod = 1e9+7;
    long long Fac[N+10],rev[N+10];
    void init()
    {
        Fac[0] = 1;
        for(int i=2; i<=N; ++i)
            Fac[i] = Fac[i-1]*i%mod;
        //对质数取模,逆元Rev(x) = x^(mod-2)
        rev[N] = fast_pow(Fac[N],mod-2);
        for(int i=N-1; i>=1; --i)
            rev[i] = rev[i+1]*i%mod;//逆元的性质
    }
    long long C(long long n,long long m)
    {
        if(!m||m==n) return 1ll;
        return Fac[n]*rev[m]%mod*rev[n-m]%mod;
    }
    

    我的代码


    E-E
    CodeForces - 558C
    题意:
    给n个正整数(n<=100000),a1,a2…an(1<=ai<=100000)
    每操作一次,可以把任意一个数乘以2或者除以2(整数除法)
    问最少操作多少次可以使这n个数都相同?

    输入:
    n
    a1 a2… an
    数据范围:
    1<=n<=100 000
    1<=ai<=100 000

    思路:
    用二进制模拟

    • 先把所有的数都写成二进制的形式按高位对齐,每一位求n个数的和,若cnt[i]==n说明n个数的这一位都是1,简记为c[i]
    • 一个数乘以2相当于在它后面加了一个0,除以2相当于删去了最后一位(0或1)
      高位 -> 低位
      3: 1 1
      5: 1 0 1
      6: 1 1 0
      c: 3 2 1
    • 我一开始的思路是这样的:
      从最高位开始,
      如果c[i]==0说明n个数该为全是0或者有的数没有这么多位,可以通过乘以2添加0;
      如果c[i]==n,说明这n个数该为均为1;如果0<cnt[i]<n 则有的为1,有的为0,因为无法凭空产生1,所以i前面的相等的数就是最后每个ai操作后的结果
      找到第一个0<cnt[i]<n的位数,己它前面有x位,所以结果为 sum(abs(bitof(a[i]-x)) i=1,2…n
    • 然后就Wa了
    • 其实还有一种情况,虽然我们不能凭空添加1,但是我们可以删去1和添加0
      看一个死亡样例:(下面6个数是二进制形式,高位对齐)
      101100 0000
      101100 0000
      101100 0000
      101100 0000
      101101
      1011
      显然,按照刚才的思路,只有前5位cnt[i]为0或n
      那么如过ai最后可以都变成10110或者1011或者101或者10或者1你应该懂我意思吧
      就是说所取前1,2,3,4,5位都可以
      取一个操作最少的就是答案
      ans = |10-5|*4 + |6-5|+|4-5| = 22
      但是其实,我们可以把第5第6个数都变为101100 0000
      第5个数除一次,乘5次,第6个数乘6次
      ans = 5+1+6 = 12显然比22小

    这是因为: 刚才的思路碰到多余的1就直接投降了,其实我们可以吧多余的1删掉,甚至还可以删掉1以后在后面添很多0
    最后a[i]变为的相等的数可能位数比x要多,设为y
    当然,二进制形式的x位之后全部是0
    我的代码


    F-F
    CodeForces - 558D
    题意:
    有一棵满二叉树,高度为h(1<=h<=50),顶点为序号1,顶点为第1层
    叶子节点都在第h层,其中,有一个出口在某个叶子节点上
    然后有q(q<=1e5)个询问,每个询问有4个数cent L R ans
    问在第cent层序号范围在[L,R]的节点的是否有出口的祖先?(自己也是自己的祖先) ans=1表示有,ans=0表示没有

    输入:
    h q
    cent1 L1 R1 ans1
    cent2 L2 R2 ans2

    centq Lq Rq ansq

    输出
    若给的数据自相矛盾输出“cheated…”
    若能判断出出口所在叶子节点的序号,输出序号
    否则输出“data is not suffient”
    数据范围:
    1<=h<=50
    0<=q<=1e5

    思路:
    离线处理,给定一组L,R,可以求出其在第h层的所有子节点[l,r]
    把ans=1的放一起,ans=0的放一起,按区间左端点排序

    • 若h=1则出口一定在1,稍加判断即可
    • 若只有ans = 1的询问,则若有两个区间完全不相交,说明两有多个出口,矛盾; 若最后求得所有区间交集为0,也矛盾;若交集长度>1则数据不充足;若区间长度为1,输出这个r
    • 若只有ans = 0的区间,则存在多个区间,是没有出口的,若若叶子节点的全集减去这些区间的交集所得的差集为0,说明没出口,矛盾; 若差集长度只有一个长度为1的区间,则是答案;若差集有多个区间,则条件不充足
    • 若ans=0和ans=1均存在 先求出全集和ans=0差集,然后求ans=1的集合时,若有两个不想交的ans=1的集合,判断是否被否定
      若存在两个不相交的集合多没有被ans=0的询问否定则矛盾:
      否则看剩下的区间若长度为1,输出答案;
      若没有区间,则也矛盾;若只剩一个长度大于1的区间,则条件不充足

    我的代码
    (代码看似长,其实后面的case 3都是复制的case 1和2)


    G-G
    CodeForces - 527C
    题意:
    有一块玻璃,h*w(1<=h,w<=2e5)划线n次,每次在玻璃上垂直或水平画一条线,问每次画完线之后最大的矩形面积
    输入:
    h w n
    ch1 x1
    ch2 x2

    chq xq
    若ch = V表示垂直划
    若ch = H表示水平画线
    数据范围:
    2<=h,w<=2e5
    1<=n<=2e5
    思路:
    矩形面积最大,一定是长和宽最大
    用set存线,用map存线之间的间距(很多人用mulitset都差不多)
    每次找到离新画的线最近的两条线,得到x1,x2
    map[x2-x1]–; map[x2-x]++; map[x-x1]++;
    更新map值即可,若键对应的值为0,删除该节点
    map的最大值为 *( --mp.end() )
    (据说这道题正解是并查集?)
    我的代码


    H-H
    CodeForces - 527D
    题意:
    N-P完全问题时间复杂度很难达到多项式的时间复杂度,如在n个点求一个最大的完全图的节点数
    本题对于节点之间边的定义有所不同。
    有n个点(1<=n<=2e5),所有点都在X轴上,每个点有坐标xi和重量wi,若两个点距离>=重量之和,则两个点之间有无向边
    求这样的完全图的最大节点数
    输入:
    n
    x1 w1
    x2 w2

    xn wn
    数据范围:
    1<=n<=2e5
    0<=xi<=1e9
    1<=wi<=1e9

    思路:
    分析见代码的注释部分
    分析过后可以转化为经典的贪心问题:
    最多可以完整的观看几个电视节目?

    我的代码


    I-I
    CodeForces - 526C
    题意:
    意思大致是有两种糖果,每种无限多,一个爱吃糖果的小怪物最多吃capacity克的糖果,每种糖果一棵的重量和带来的开心度分别为wi和ei
    求最大的开心度
    输入:
    capacity
    w1 e1
    w2 e2
    数据范围:
    均为[1,1e9]

    思路:
    有人说用完全背包做
    我是直接w1取x个0-1e7个,暴力更新答案,然后w2再搞一遍
    [我的代码(https://paste.ubuntu.com/p/BSMv9JK8Df/)


    J-J
    CodeForces - 526D
    题意:
    大致是说给一个长度为n的字符串S,为每个前缀是否可以看成是K+1个A和K个B交错组成的如下形式的字符串
    ABABA…A (K+1个A,K个B, 其中A或B可以是空串)

    输入:
    n K
    S

    输出
    长度为n的字符串,若长度为i的前缀可以看成ABA…A(K个B)这种形式,就在第i位输出1,否则输出0

    数据范围:
    1<=n,k<=1000 000

    思路:
    由于所求的串是循环的,所以我们需要知道每个前缀的循环节
    可以用kmp算法中的next数组求得
    kmp求最小循环节
    定理:若长度为len的字符串S存在最小循环节,则循环节的长度L = len - next[len]
    循环节为S的子串[S0,S1,S2…S(L-1)]
    看一个例子:
    15 2
    abcabcabcabctql
    1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 (index)
    a b c a b c a b c a b c t q l (S)
    0 0 0 1 2 3 4 5 6 7 8 9 0 0 0 (Next)
    1 1 1 1 1 2 2 2 3 3 3 4 1 1 1 (x)
    循环节的长度为L,则循环次数x = len/L(向下取整)
    现在有三种情况:

    • case 1:B串为空串,则需要出现K+1个完整的A
      所以这时,只要保证len%L=0且x%(k+1)=0即可
    • case 2:A串为空串,则需要出现K个完整的B
      与上一种情况同理,len%L==0 且 x%K=0
    • case 3: A串和B串都不为空
      若(最小的)循环节为D,则
      当len%L=0时:原串可以表示为DDD…D(x个D)
      当len%L!=0时,原串可以表示位DDD…Dd(其中有x个D,d为D长度为len%L的前缀)
      len%L!=0的情况比较一般,因为我们可以吧D也看作是d
      设D = d(前缀) + p(除去前缀的后缀)
      设AB = C
      则A可以写成DD…D(D的个数可能为0)的形式,B可以写成pDD…D(D的个数可能为0)的形式
      CCC…CA(K个C)
      C.length = len/L
      A.length = len%L
      由于C.length > A.length,则一个充分条件就是len/K > len%L
      只要满足了这个条件,那么就可以把长度为L的前缀看成C(A+B),把长度为len%L的前缀看成A
      我能不能说除了这种方法构造不出来ABABA的串,所以这也是必要条件

    我的代码


    K_K
    CodeForces - 535C
    题意:
    题意有点儿不好读懂
    给一个无限长的首项为A公差为B的等差数列
    有多个询问,每次给L m t
    表示最多可以操作t次,每次最多可以使m个数减一,
    问从L开始,最多可以使多长的区间都减为零?
    输入:
    A B n
    一下为n组询问:
    l t m
    数据范围:
    A,B <= 1e6
    n<=1e5

    思路:
    二分:由于最多操作t次,所以区间右边端点<=t
    区间和小于等于t*m
    这道题让我知道即使开了取消同步cin,cout还是妥妥的TLE

    我的代码


    L-L
    CodeForces - 535D
    题意:
    给一个字符串P,要构造一个长度为n的字符串S,这个字符串要满足匹配子串P至少m次,给出m个匹配的位置posi,表示构造出的字符串P的第posi位到第posi+p.length-1位的子串必须和p完全一样,求能构造出多少种满足条件的字符串(答案对1e9+7取模)
    输入:
    n m
    pos1 pos2 … posm

    数据范围:
    1 ≤ n ≤ 1000 000
    0 ≤ m ≤ n-|p|+1

    思路:
    照题意模拟。pos从小到大排序,若两个pos之差>=lengthOf§则一定有解,若大于,则未涉及的位置可以任意取26个字母,cnt += posj-posi
    两个串有重叠,则要满足题意,相交的部分要为模式串的前缀和后缀的公共部分
    预处理出所有前缀和后缀相同的公共部分,用KMP的Next数组可以得到模式串前后缀最长的公共部分
    存在多个相同的前后缀,则一定有循环:
    p[1,2] == p[19,20] 且 p[1,2,3,4] == p[17,18,19,20]
    =>p[1,2]==p[3,4]==p[19,20]==p[17,18]
    可以预处理出字符串P所有可以和前缀匹配上的后缀的长度(有点儿抽象,看下面这个例子)
    例如abcabcababcczzzzzabcabcabc
    其中所有满足条件的后缀的长度就是3,6,9
    然后按题意模拟,如果重叠了且重叠的后缀长度和前缀无法匹配,则直接输出0,return 0;
    若不冲突,则输出26^cnt

    我的代码


    ps: 第一次markdown,还是挺好用的
    从2月22号早上开始写,火车下铺写了一下午,写到电脑没电,然后今天晚上终于写完了。

    完成时间:2019/2/23 21.07

    地点: 1105

  • 相关阅读:
    datum of data matrix
    data matrix with opensource
    wps出现“文档已被其他应用程序锁定,是否以只读模式打开”
    error MSB3073解决办法
    vc6下dll调试
    往客户机子上装dll时,报缺失mfc42d.dll
    进程通信编码和解码
    java后端选型20200729
    Git安装与使用
    Kitty基于Spring Boot、Spring Cloud、Vue.js、Element实现前后端分离的权限管理系统
  • 原文地址:https://www.cnblogs.com/Apare-xzc/p/12243672.html
Copyright © 2020-2023  润新知