最近一直很忙,希望我能够写完。
这道题目并不难,却很复杂。只要你有耐心,根据题解,一定能够做出来。唯一的困难就是,你常常半途而废。能够看完题解的,应该是一个有耐心的人。
这个题目应该是庞果网上目前为止最难的一道题目了,今天在群中大神FancyMouse的提点下,找到一篇名为“Recursive Sequence”的文章,完成了m项递推式的O(m^2logn)时间复杂度的优化,这是这道题目的最终的优化,应该说,完成这个优化,这道题就没有可以优化的地方了,当然,边边角角的优化也是可以提高效率,但终究起不了大作用。
题目将逆元的运用、多项式系数计算、m项递推式优化这三个我认为主要的知识点融合在了一起,不能不说,这是一道很好的题目(个人认为)。
我的想法还是根据群里给出的题解,但是那个写的有些乱,又不详细,喜欢看的人很少,我将按照自己对题解的梳理,叙述这道题目的解法。
题目详情:
用n个不同的字符(编号1 - n),组成一个字符串,有如下2点要求:
1、对于编号为i的字符,如果2 * i > n,则该字符可以作为最后一个字符,但如果该字符不是作为最后一个字符的话,则该字符后面可以接任意字符;
2、对于编号为i的字符,如果2 * i <= n,则该字符不可以作为最后一个字符,且该字符后面所紧接着的下一个字符的编号一定要大于2 * i。
问:有多少长度为M且符合条件的字符串。
例如:N = 2,M = 3。则abb,bab,bbb是符合条件的字符串。剩下的均为不符合条件的字符串。
输入:N,M(2 <= N,M <= 1 * 10^9)
输出:满足条件的字符串的个数,由于数据很大,输出该数Mod 10^9 + 7的结果。
函数头部:int validString(int n , int m){}
题目的叙述简单,但是题目的难度却很大,而难度大的原因,来自于字符的数量和字符创的长度都是十的九次方。这个数量很庞大,为此,我们需要激昂庞大的问题拆解成能够高效完成的小问题。根据题解,不断解决一个小的模块,直到解决整个问题。
理论基础
题解首先给出的是一个定义。【合法链】:从一个字母开始,后边的每一个字母编号都大于等于前一个的2倍,这样尽可能的连接字母,直到不能再连接,即最后一个字母的编号满足2 * i > n。这样,后边的字母必定不满足大于等于前一个字母编号的2倍,就不是这个【合法链】的一部分了。
有了这个定义,我们可以总结如下规律:一个合法的字符串是有若干【合法链】组成的;对于每一个字符串,划分成【合法链】的方法是唯一的。
关于规律我不给出证明,但它是正确的。简单说一下,我们把字母分类,所有编号为i,且2 * i <= n的字母归为A类,其余的归为B类。B类字母的编号i满足2 * i > n。任意一个【合法链】只有一个B类字母,其余的全部是A类字母。任意一个合法字符串,我们按照B类字母将字符串断开,一个B类字母之前的所有A类字母