现在我们得到了一个可做串 s。考虑用 26m 减去不合法的情况,即从每个位置开始的子串字典序都大于等于 s 的情况。大于等于 s 等价于大于 pred(s)(最大的比 s 字典序小的字符串)。
只考虑 n≤m 的情况(如果 m>n,那么只需要看一个前 m 位恰好等于 s1,m 的串的重复是否比 s 小。根据 s 的强可做性,这个是必然的。因此只需要算大于 s 的情况即可,因为等于 s 也是合法的)。
由于 s 的后缀严格大于前缀,即 sn>s1,其 pred 就是将末尾减一的结果(不需要退位)。可以发现得到的串必定是可做的,即任意子串大于等于等长的前缀。
以下我们设 s 是可做的(就是之前那个 pred(s)),且 n=∣s∣<m,求有多少个长度为 m 的串 t 满足 t 的无穷重复的任意长度为 n 的子串都大于 s。
t 的无穷重复中任意子串大于 s,等价于说把 t 看成一个环之后,其任意长为 n 的子串字典序大于 s。下面我们先把 t 看成一个环。称满足条件的环是合法环。
定义一个串 p 是好的,当且仅当 ∣p∣≤n,且 p1,∣p∣−1=s1,∣p∣−1,p∣p∣>s∣p∣。
我们有如下引理:
引理 2
由若干个好串拼接而成的环 t 是合法环。并且对于任何一个合法环,将其表示成好串的拼接的方式是唯一的。
证明:引理有三个部分,我们分别证明:
先证明好串的拼接是合法的。如果有一个好串的拼接,对于其任意一个长为 n 的子串 q,q 一定有一个前缀 q1,k 是某个好串的后缀。
设这个好串为 p,那么 q1,k=p∣p∣−k+1,∣p∣>s∣p∣−k+1,∣p∣≥s1,k。其中大于号是因为好串的前面部分和 s 对应部分相等而最后一个字母大于 s 的对应字母,
大于等于号是因为 s 的可做性。于是 q1,k>s1,k,显然有 q>s。
再证明合法环可以分解成好串的拼接。对于一个合法环,找到其最小表示法 t(即,其循环排列中字典序最小者),那么从开头开始对 s 做匹配,每次发现某个位置比 s 的相应位置大的时候划分出一个好串。
只需要证明匹配到末尾的时候不可能还剩下没有匹配完的部分。如果到了末尾还没有匹配完,那么 t 必定有一个后缀与 s 的某个前缀相等(就是匹配剩下的部分)。
设 t∣t∣−k+1,∣t∣=s1,k,那么必定有 t1,k=s1,k,否则的话 t 的某个长度小于等于 k 的前缀是好串,而好串必定比 s 字典序大,这和 t 是最小表示不符;
但是既然 t1,k=s1,k,因为 t 实际上首尾是相邻的(是个环),所以 t∣t∣−k+1,∣t∣+t1,k=s1,k+s1,k 也是其子串,因此必须要大于等于 s1,2k,即 s1,k≥sk+1,2k,
这样的话,根据 s 的可做性又有 sk+1,2k≥s1,k,于是 s1,k=sk+1,2k。这样的话必须有 t1,2k=s1,2k,因为 t 存在一个与 s1,2k 相等的子串,而 t 是最小表示法从而 ≤s1,2k, t 又是合法串因此 t1,2k≥s1,2k。这样的话,重复之前的步骤,可以发现 s1,k=sk+1,2k=s2k+1,3k=…,而 t1,pk=s1,pk。
当 p 充分大的时候,这说明 s 必须无限长,这显然是矛盾的,因此原来的假设(t 最后匹配好串没有匹配完)是不成立的。
最后要证明好串拆分是唯一的。事实上如果固定起点,那么好串划分一定是唯一的,即上面的构造方式;而任选 t 的某个最小表示法,根据上面的证明容易发现不可能存在跨越首尾的好串,于是可以直接从这个点开始划分。
这样,我们就完成了引理的证明。□
这样的话,相当于对好串的拼接方式计数。显然对于某个长度,这个长度的好串个数是容易计算的(就是 ‘z’ 减去 si),那么设 ai 表示长为 i 的好串个数,fi 表示好串排成一排长度和为 i 的方案数,显然有
voidINV(const LL *A, int n, LL *B){ if (n == 1) returnvoid(B[0] = pow_mod(A[0], mod - 2)); int m = (n + 1) / 2; INV(A, m, B);
static LL t1[N], t2[N]; int l = getLen(n + n); for (int i = 0; i < n; ++i) t1[i] = A[i]; for (int i = n; i < l; ++i) t1[i] = 0; for (int i = 0; i < m; ++i) t2[i] = B[i]; for (int i = m; i < l; ++i) t2[i] = 0;
DFT(t1, l); DFT(t2, l); for (int i = 0; i < l; ++i) t1[i] = t2[i] * (2 - t1[i] * t2[i] % mod) % mod; IDFT(t1, l);
for (int i = m; i < n; ++i) B[i] = t1[i]; }
char s[N]; int n, m, nxt[N]; LL A[N], B[N];
intmain(){ scanf("%d%s", &m, s); n = strlen(s); nxt[0] = nxt[1] = 0; for (int i = 1, j = 0; i < n; ++i) { while (j && s[j] != s[i]) j = nxt[j]; nxt[i + 1] = j += s[j] == s[i]; } for (int i = 1; i < n; ++i) if (s[i] < s[nxt[i]]) n = i; while (nxt[n]) --n; if (n > m) ++s[(n = m) - 1]; --s[n - 1]; A[0] = 1; for (int i = 1; i <= n; ++i) A[i] = s[i - 1] - 'z'; InitDFT((m + 1) * 2); INV(A, m + 1, B); LL ans = (pow_mod(26, m) - B[m]) % mod; for (int i = 2; i <= n; ++i) ans = (ans + (i - 1) * A[i] * B[m - i]) % mod; printf("%lld\n", (ans + mod) % mod); }