ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 135E - Weak Subsequence(分析性质+组合数学)

2022-01-03 16:02:24  阅读:209  来源: 互联网

标签:子串 le int sum Weak Codeforces Subsequence 长度 MOD


MARK on 2022.1.3:由于本人觉得“组合数学杂题选做”这篇博客太累赘了,故将其删除并将其中所有题解都单独开一篇博客写入。

Codeforces 题目传送门 & 洛谷题目传送门

组合数学好题。

Key observation:对于一个字符串 \(s\),其最长的“弱子串”的长度等于 \(|s|\) 减去 \(\min(s\text{最长的字符都不同的前缀},s\text{最长的字符都不同的后缀})\)。

证明:我们先来证一个引理:如果一个子串是 \(s\)​​ 的弱子串,那么其对应的符合要求的子序列必然可以通过在子串的基础上移动一个字符得到。该定理的证明大概就,考虑一个子序列 \(i_1,i_2,\cdots,i_k(i_t<i_{t+1})\)​ 和一个子串 \(j_1,j_2,\cdots,j_k(j_t<j_{t+1})\)​,如果它们公共的元素个数 \(<k-1\)​,那么我们考虑最大的 \(t\)​ 满足 \(i_t<j_t\)​,由于 \(t\)​ 是符合要求的下标中最大的,必然有 \(i_{t+1}\ge j_{t+1}\)​,因此 \(j_t\sim i_{t+1}\)​ 之间没有任何被选择的元素,我们完全可以直接将 \(i_t\)​ 改为 \(j_t\)​,这样重合部分大小会 \(+1\)​,又由于原本重合部分大小 \(<k-1\)​,因此改完之后子序列还是符合弱子序列的要求,故我们的修改是符合要求的。如此进行下去直至重合部分达到 \(k-1\)​ 即可。

于是我们不妨考虑一个子串,由于我们只能移动一个元素,因此我们只能移动第一个或者最后一个元素,如果我们移动第一个元素,那么我们找到 \(s\)​ 最长的字符都不同的前缀长度 \(len\)​,并令该子串为 \(s[len+1…|s|]\)​,容易证明这样操作是所有只移动第一个元素的情况中最优的,对于移动最后一个元素的情况也是类似的,两者取个 \(\max\)​ 就是 \(|s|-\min(s\text{最长的字符都不同的前缀},s\text{最长的字符都不同的后缀})\)。

接下来考虑如何计算答案。考虑容斥,拿弱子串长度 \(\le w\) 的方案数减去弱子串长度 \(\le w-1\) 的方案数即可得到答案,于是问题转化为求最长弱子串长度 \(\le w\) 的方案数。根据上面的式子可以看出,长度 \(\le w\) 的长度都符合要求,方案数 \(\sum\limits_{i=1}^wk^i\),一波等比数列求和/分治带走,对于长度为 \(w+i(i\in[1,k])\)​ 的情况,字符串符合要求当且仅当前 \(i\) 位互不相同,后 \(i\) 位也互不相同,继续分情况:

  • 如果 \(2i\le w+i\),那么前 \(i\) 位与后 \(i\) 位是独立的,方案数 \((k^{\underline{i}})^2·k^{w-i}\)。
  • 否则记 \(c=2i-(w+i)\),那么中间方案数 \(k^{\underline{c}}\),两侧方案数都是 \((k-c)^{\underline{i-c}}\),总方案数 \(k^{\underline{c}}·((k-c)^{\underline{i-c}})^2\)

而对于长度 \(>w+k\) 的字符串,由于字符集大小为 \(k\),显然不符合要求。

直接计算即可,时间复杂度 \(k\log w\)。

const int MAXN = 1e6;
const int MOD = 1e9 + 7;
int k, w, fac[MAXN + 5], ifac[MAXN + 5];
int qpow(int x, int e) {
	int ret = 1;
	for (; e; e >>= 1, x = 1ll * x * x % MOD)
		if (e & 1) ret = 1ll * ret * x % MOD;
	return ret;
}
void init_fac(int n) {
	for (int i = (fac[0] = ifac[0] = ifac[1] = 1) + 1; i <= n; i++)
		ifac[i] = 1ll * ifac[MOD % i] * (MOD - MOD / i) % MOD;
	for (int i = 1; i <= n; i++) {
		fac[i] = 1ll * fac[i - 1] * i % MOD;
		ifac[i] = 1ll * ifac[i - 1] * ifac[i] % MOD;
	}
}
int calc_spw(int t, int k) {
	if (!t) return 0; if (t == 1) return k;
	int mid = t >> 1, sum = calc_spw(mid, k);
	sum = (sum + 1ll * sum * qpow(k, mid)) % MOD;
	if (t & 1) sum = (sum + qpow(k, t)) % MOD;
	return sum;
}
int calc_A(int n, int k) {
	if (n < k) return 0;
	return 1ll * fac[n] * ifac[n - k] % MOD;
}
int calc(int k, int w) {
	int ss = calc_spw(w, k);
	for (int i = 1; i <= k; i++) {
		int len = i + w;
		if (i + i <= len) ss = (ss + 1ll * calc_A(k, i) * calc_A(k, i) % MOD * qpow(k, len - i - i)) % MOD;
		else {
			int cap = i + i - len;
			ss = (ss + 1ll * calc_A(k, cap) * calc_A(k - cap, i - cap) % MOD * calc_A(k - cap, i - cap)) % MOD;
		}
	}
//	printf("%d %d %d\n", k, w, ss);
	return ss;
}
int main() {
	scanf("%d%d", &k, &w); init_fac(MAXN);
	printf("%d\n", (calc(k, w) - calc(k, w - 1) + MOD) % MOD);
	return 0;
}

标签:子串,le,int,sum,Weak,Codeforces,Subsequence,长度,MOD
来源: https://www.cnblogs.com/ET2006/p/Codeforces-135E.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有