ARC114C题解

简述题意

  • 给你两个长为 \(n\) 的可重数列,一个叫 \(A\),另一个叫 \(X\)\(A\) 中的元素取值范围为 \(1 \sim m\)\(X\)中的元素初始值都是 \(0\)
  • 每次你可以选择 \(X\) 中的 \([l, r]\) 区间,让他和 \(v\)\(max\),将这段区间里的数都变成这个最大值。
  • \(X\) 最少经过 \(f(A)\) 次操作可以变成 \(A\),问对于所有的 \(m ^ n\)\(A\)\(f(A)\) 之和。

思路

  • 将问题转化成给 \(A\) 里填数。
  • 考虑每新来一个数 \(p\) 对我 \(f(A)\) 的影响。
    • \(p\) 没有出现过,那么我的 \(f(A)\) 应加一。
    • \(p\) 出现过,记录之前出现的位置为 \(lst\),那么如果对于 \(\forall k \in [lst, i], val_k \ge p\),显然我可以通过对 \(lst\) 操作来达到让这里变成 \(p\) 的目的(因为中间的数不会被影响,区间取 \(max\)),操作数不用加,反之则需要加一。

推式子

  • 考虑如何求出每一个 \(f(A)\),因为我们知道什么情况下是不需要加一的,所以直接用总情况数减去不需要加一的情况就行了。记 \(g(i, x)\) 表示在 \(i\) 的位置增加一个数 \(x\) 的操作数。

\[g(i, x) = m ^ {i - 1} - \sum\limits_{k = 1}^{i - 1} (m - x) ^ {i - k - 1} \cdot m ^ {k - 1} \]

  • 其中 \(k\) 枚举的是上一个 \(x\) 出现的位置,\((m - x)\) 表示所有比 \(x\) 大的数,他们可以在 \([k + 1, i - 1]\) 任意分布,对于其他的 \(k - 1\) 个位置随便放就行了。

  • 这里有一个细节,对于每一个 \(x\) 这个式子是可以递推的,首先对于 \(i\) 每增大 \(1\)\((m - x)\) 的次方就多一,所以应该先乘上 \((m - x)\) 其次我们可以把乘 \(m ^ {k - 1}\) 单独拿出来,因为对于增大的 \(i\) 上一个和式和现在的和式之间只差一个 \(m ^ {k - 1}\) (抛去次方的变化来看)。

  • 最后统计答案就只需要:

\[ans_i = \sum\limits_{x = 1} ^ {m} ans_{i - 1} + g(i, x) \]

Code

#include <bits/stdc++.h>
#define Re register int
#define LL long long
#define fr(x, y, z) for(Re x = y; x <= z; x ++)
#define fp(x, y, z) for(Re x = y; x >= z; x --)
#define fuc(x, y) inline x y
#define WMX aiaiaiai~~
using namespace std;
namespace kiritokazuto {
	fuc(char, getc)(){
		static char buf[1 << 18], *p1, *p2;
		if(p1 == p2){
			p1 = buf, p2 = buf + fread(buf, 1, 1 << 18, stdin);
			if(p1 == p2)return EOF;
		}
		return *p1++;
	}
	fuc(LL, read)() {
		LL x = 0, f = 1;char c = getc();
		while(!isdigit(c)){if(c == '-')f = -1; c = getc();}
		while(isdigit(c)){x = (x << 1) + (x << 3) + (c ^ 48); c = getc();}
		return x * f;
	}
	template <typename T> fuc(void, write)(T x){
		if(x < 0)putchar('-'), x = -x;
		if(x > 9)write(x / 10);putchar(x % 10 | '0');
	}
} 
using namespace kiritokazuto;
const int maxn = 1e5 + 1000, Inf = 2147483647, Mod = 998244353, lim = 2e5 ;
LL sum[5010];
LL lst, ans;
LL pows[5010];
int n, m;
signed main() {	
	n = read(), m = read();
	pows[0]  = 1;
	int lim = max(n, m);
	fr(i, 1, lim)pows[i] = pows[i - 1] * m % Mod, sum[i] = 1;
	lst = m;
	ans = 0;
	fr(j, 1, m)ans = (ans + (lst + (pows[1] - sum[j] + Mod) % Mod) % Mod) % Mod;
	fr(i, 3, n) {
		lst = ans, ans = 0;
		fr(j, 1, m)sum[j] = (sum[j] * (m - j) % Mod + pows[i - 2]) % Mod;
		fr(j, 1, m)ans = (ans + (lst + (pows[i - 1] - sum[j] + Mod) % Mod) % Mod) % Mod;
	}
	write(ans);
	return 0;
}

posted @ 2022-11-07 19:55  kiritokazuto  阅读(47)  评论(3编辑  收藏  举报