[ABC270Ex] add 1 题解
[ABC270Ex] add 1 Solution
更好的阅读体验戳此进入
题面
给定序列 $ A_n $,存在 $ n $ 个初始为 $ 0 $ 的计数器,每次可以进行如下操作:选定一个计数器使其变为 $ 0 $ 并使得其它所有计数器 $ +1 $。求期望的使对于每个 $ i $ 满足第 $ i $ 个计数器的数值不小于 $ A_i $ 的操作次数。对 $ 998244353 $ 取模。
Solution
大概是一道没有什么高端的算法,仅靠推式子的难度评黑的题。
首先我们不难想到,如果设当前计数器的值为 $ C_i $,那么我们的目的就是要满足所有 $ A_i - C_i \le 0 $。
然后不太严谨地思考一下不难发现,我们每次是使除了选择的其它的计数器都加一,所以拖后腿的一定是 $ \max{A_i - C_i} $,令 $ k = \max{A_i - C_i} $ 则状态将仅与 $ k $ 相关。
于是此时不难想到一个较为简单的状态:令 $ F(k) $ 表示状态为 $ k $ 时的期望操作次数。
显然 $ F(0) = 0 $,考虑转移,不难发现状态 $ k $ 肯定对应这一个或者一段 $ A $,因为序列 $ A $ 是不降的,所以我们假设第一个对应的前一个为 $ A_{idx} $,显然对于前 $ idx $ 个的操作都会使 $ k \leftarrow k - 1 $,对于 $ idx $ 之后的操作都会使当前的 $ k $ 变为新的 $ A_i $,所以转移显然为:
转化一下:
现在不难发现即较小的都在左侧,较大的都在右侧,不过这个转移仍然不行,也就是我们是已知 $ F(0) $ 然后想要求 $ F(A_n) $,但是这个式子却是需要反过来转移的,所以需要优化。
考虑令 $ G(k) $ 表示从状态 $ 0 $ 转移到状态 $ k $ 的期望次数,所以显然有 $ G(k) + F(k) = F(A_n) $。移个项然后带进去 $ F $,显然有:
显然 $ F(A_n) $ 抵消了,则:
类比一下之前的推出来:
显然:$ G(A_n) = 0 $,我们要求 $ G(0) $,符合转移。
不难发现对于固定的 $ k $ 一定对应着固定的 $ idx $,也就是 $ \dfrac{N - \sum_{i = idx + 1}^N G(A_i)}{idx} $ 可以认为是一个常数,令其为 $ C $,若再令 $ B = \dfrac{N}{idx} $,所以有 $ G(k - 1) = B \times G(k) + C $,属于较为简单的转移,考虑矩乘优化,构造矩阵的过程也是平凡的,得到:
对于 $ [A_i, A_{i + 1}] $ 之间的部分的所有 $ k $ 显然 $ B $ 和 $ C $ 是相同的,这一部分用矩阵快速幂优化一下即可,最后复杂度应为 $ O(2^3 n \log A_i) $。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MOD (998244353ll)
template < typename T = int >
inline T read(void);
struct Matrix2{
ll v00, v01, v10, v11;
friend Matrix2 operator * (const Matrix2 &a, const Matrix2 &b){
return Matrix2{
(a.v00 * b.v00 % MOD + a.v01 * b.v10 % MOD) % MOD,
(a.v00 * b.v01 % MOD + a.v01 * b.v11 % MOD) % MOD,
(a.v10 * b.v00 % MOD + a.v11 * b.v10 % MOD) % MOD,
(a.v10 * b.v01 % MOD + a.v11 * b.v11 % MOD) % MOD
};
}
};
Matrix2 base{1, 0, 0, 1};
ll qpow(ll a, ll b){
ll ret(1), mul(a);
while(b){
if(b & 1)ret = ret * mul % MOD;
b >>= 1;
mul = mul * mul % MOD;
}return ret;
}
ll inv(ll v){return qpow(v, MOD - 2);}
Matrix2 qpow(Matrix2 a, ll b){
Matrix2 ret(base), mul(a);
while(b){
if(b & 1)ret = ret * mul;
b >>= 1;
mul = mul * mul;
}return ret;
}
int N;
ll A[210000];
int main(){
N = read();
for(int i = 1; i <= N; ++i)A[i] = read < ll >();
Matrix2 ans{0, 1, 0, 0};
ll cur(0);
for(int i = N - 1; i >= 1; --i){
ll B = N * inv(i) % MOD, C = (N - cur) * inv(i) % MOD;
ans = ans * qpow(Matrix2{B, 0, C, 1}, A[i + 1] - A[i]);
(cur += ans.v00) %= MOD;
}printf("%lld\n", (ans.v00 % MOD + MOD) % MOD);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2023_01_27 初稿