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;
}
愿你在冷铁卷刃之前,得以窥见天光