• Mutual Training for Wannafly Union #9


    A(SPOJ NPC2016A)

    题意:给一个正方形和内部一个点,要求从这个点向四边反射形成的路线的长度

    分析:不断做对称,最后等价于求两个点之间的距离

    B(CF480E)

    题意:求01矩阵内由0组成的最大正方形,但这里有修改操作,每次操作把一个0位置修改成1。矩阵大小<=2000*2000,操作次数<=2000

    分析:离线倒序+悬线法+单调队列维护

       首先离线,倒着从前往后做

       先预处理每个0位置向上、向下最多能延展多少

       对于修改就暴力修改,时间复杂度是O(kn)的

       问题是如何维护询问的结果

       注意到每次修改了一个位置(x,y),那么目前最大的边长一定在第x行产生

       我们需要快速维护一个行x的每一段区间向上、向下最多能形成多大的正方形

       每次从左往右扫描,得到一个[l,r],表示正方形的左右边界

       从小到大枚举l,发现r是单调的,所以这个东西是可以用单调队列来维护的

       时间复杂度O(nm+kn+km)

       思考:为什么需要倒序?(因为倒序之后的操作变成了删除一个点(x,y),那么可能的最大正方形一定可以由第x行信息求到,如果顺序的话,相当于把一个正方形裂开,就无法处理了)

       事实上,如果正序的话,要想保证结果的正确性,应该要对每个行都做一次扫描,不过那样时间复杂度就和暴力一样了

       有个很巧妙的做法,就是对行分治,分成上面和下面,上面单独做,下面单独做,合并的话就以分界线扫描一次就ok了

       这样时间复杂度是O(nm+kn+kmlogn),多带一个log,也是能过的

    C(CF193B)

    题意:有4个长度为n(n<=30)的数组a[],b[],k[],p[],和一个给定的常数r,其中p[]是一个排列,以及操作的总次数u

       有两种操作:

        操作1:ai^=bi

        操作2:ai=a[pi]+r

       现在要在u次操作的情况下最大化Σai*ki

    分析:搜索+剪枝

       范围很小,想到搜索

       但是爆搜是不行的O(n2^n)是超时的

       发现异或的相消性,偶数个操作1连一起就会消失

       考虑这样一个变长序列:1 2 2 1 2 ……

       其中不能有相邻的1,一个1代表着一段奇数个操作1

       这种序列在极端情况下f(30)的方案数可以通过递推式f(i)=f(i-1)+f(i-2)求得,是8e6级别的,是可以接受的

       还剩一个问题,如何知道这个变长序列对应的长度是u呢?

       其实只要u和len奇偶性相同就行了

    D(CF346B)

    题意:求s1和s2的最长公共子序列,但是这个最长公共子序列不能有子串是virus,三个串长度都小于等于<=100

    分析:dp+next转移

       dp[i][j][k]表示s1的前i个字符,s2的前j个字符,和病毒串匹配到第k位的最长公共子序列长度

       通过预处理next转移一下就行了

       此题细节很多,而且需要输出方案,debug了好久

    E(CF346A)

    题意:给出一组数(n<=100),两个人博弈,每次从中选出两个数x,y,要使得|x-y|不在序列中出现,然后把|x-y|加入序列,不能操作的人就输了,问先手赢还是后手赢?

    分析:数学分析

       首先这个游戏肯定持续的轮数是固定的,根据这个奇偶就可以判断谁赢,所以问题的关键是求游戏进行多少轮

       每次取两个数相减,发现这其实是辗转相减,最后会剩下两个数的最大公约数

       那么什么时候不能操作呢?

       就是最后的序列是d 2d 3d 4d .... md这时候,就无法操作了

       容易知道这个d就是初始所有数的gcd

       那么轮数就是m-n了,那么m怎么求呢?

       m当然就是最大数/d了……

       从而得出了一个神奇的结论?(定理?)——两个互质的素数p,q(p<q),放到一个序列里,从这个序列取出两个数相减,最后会得到1~q之间所有整数

    F(319A)

    题意:求一个序列的逆序对数(对1e9+7取模),这个序列是ai=i xor x (x是输入的常数,是一个100位以内的二进制数)

    分析:递推

       考虑从低位向高位递推

       f(i)表示前i位逆序对数

       那么对于第i+1位,如果x[i+1]=0,这说明对于之前的0~2^i-1个没有影响,而后面2^i~2^(i+1)-1其实相当于是copy前面,只不过最高位是1

       所以此时f(i+1)=2*f(i)

       那么如果x[i+1]=1,这时候相当于把0~2^i-1放到后面的一半区间,2^i~2^(i+1)-1放到前面的一半区间(内部状态还是copy的),前面部分和后面部分形成了多余的逆序对

       所以f(i+1)=2*f(i)+2^i * 2^i

       

  • 相关阅读:
    第十五周作业
    十三周作业
    第十三周上机作业
    第十二周作业
    第十二周作业
    第十一周作业
    第十一周上机作业
    第十次上机作业
    第九周上机作业
    安卓第一周
  • 原文地址:https://www.cnblogs.com/wmrv587/p/6859212.html
Copyright © 2020-2023  润新知