ARC-114 C- Sequence Scores 计数

ARC-114 C- Sequence Scores 计数

题意

给定长度为(n)的可重数列(A),(A)中元素的范围是(1-M)

给定长度为(n)的可重数列(X),初始时刻元素全部为(0)

每次可以进行操作([l,r,x])对数列(X)([l,r])区间([l,r])取操作(max(v,x[i]))

记某可重数列(A(w))最少经过(c)次操作可以得到(X)

(sum c_{A_(i)}) ,(A(i))为所有可能的可重数列

[1leq n,mleq5000 ]

分析

动态地认为每次向已经存在的(A)中加入一个数来记录答案。

假设当前加入的数为(x)

  • (x)不在(A)中出现,(c++),因为必须花费一次来得到这个数
  • (x)(A)中出现过,(x_{pre})(x)之间的所有数都大于(x),这样不需要额外花费1,因为可以一次性得到这些(x)
  • (x)(A)中出现过,(x_{pre})(x)之间不是所有数都大于(x),那么必然要额外花费1

因此新加入的数带来的贡献全部由1和3组成,记贡献为(S_{i,x})

[S_{i,x} = m^{i - 1} - sum_{k = 1}^{i - 1}(m - x)^{i - 1 - k} imes m^{k - 1} ]

其中(k)表示出现(x)的位置,那么([k,i - 1])之间的所有数取值范围是([x + 1,m])。其他地方数任意取即可。

[ans_i = sum_{x = 1}^{m} ans_{i - 1} + S_{i,x} ]

复杂度(O(nm))

其中(sum_{k})的和式可以用前缀和递推

代码

int main(){
	int n = rd();
	int m = rd();
	vector<ll> sum(m + 1,1);
	ll ans = m;
	ll pre = 0;
	vector<ll> pow(n + 1);
	pow[0] = 1;
	for(int i = 1;i <= n;i++)
		pow[i] = (ll)pow[i - 1] * m,pow[i] %= MOD;
	for(int i = 2;i <= n;i++){
		pre = ans;
		ans = 0;
		if(i > 2) {
			for(int j = 1;j <= m;j++)
				sum[j] = (ll) sum[j] * (m - j) % MOD + pow[i - 2],sum[j] %= MOD;
		}
		for(int j = 1;j <= m;j++)
			ans += ((ll)pre + pow[i - 1] - sum[j] + MOD) % MOD,ans %= MOD;
	}
	cout << ans;
}
原文地址:https://www.cnblogs.com/hznumqf/p/14537172.html