UOJ182 a^-1 + b problem 解题报告
题目描述
有一个长度为\(n(n\le 10^5)\)的数列,在模\(M\)意义下进行\(m(m \le50000)\)次操作,每次操作形如以下两种形式:
1 \(x\) 表示每个数加\(x(0 \le x<M)\);
2 表示每个数对模数\(M\)取逆元,保证逆元存在。
输出每次操作后所有数的和,对\(M\)取模。这里\(M=998244353\)。
简要题解
设原始数列为\(x_i\)。对于一个初始的数\(x\),经过第i个操作后一定可以写成\(\dfrac {a_i \times x+b_i} {c_i \times x+d_i}\)的形式。先用线性时间求出参量\(a_i,b_i,c_i,d_i\),于是问题转化为对每个\(i\),求出\(\displaystyle \sum\limits_{j = 1}^n {\frac{{{a_i}{x_j} + {b_i}}}{{{c_i}x_j + {d_i}}}} \)。先将整数提取出来,只需考虑\(\displaystyle \sum\limits_{j = 1}^n {\frac{{e_i}}{{{c_i}x_j + {d_i}}}} \)。
(1)若\(c_i=0\),则直接计算即可;
(2)否则,对每个\(i\)可以归一化为求\(\displaystyle \sum\limits_{j = 1}^n {\frac{{{1}}}{{{x_j} + {t_i}}}} \)。
将分母通分,则转化为\(\dfrac {P(t_i)} {Q(t_i)}\),其中\(P,Q\)为\(t_i\)的不超过\(n\)次多项式。
这里\(Q(x)=(x+x_1) \cdots (x+x_n)\)。考虑如何快速求出\(P\)。不难发现\(P\)正是\(Q\)的导数。
于是问题转化成了多点求值问题。可在\(O(n(\log n)^2+m(\log m)^2)\)时间复杂度求解。
还应注意到不会出现\(P(t_i)=Q(t_i)=0\)的情况,因为根据洛必达法则,此时极限趋于无穷大,不会是有限值,而题目保证了逆元存在。
说明
最近看了大量多项式应用的问题,绝大多数都是多项式逆元,这是见到的第一道应用多项式的多点求值的问题(非裸题),搞明白后不禁感叹:好题啊!佩服出题人系列。
核心代码
1 int x[100001], y[60001], w[60001], k[60001]; 2 int ans1[60001], ans2[60001]; 3 int main() 4 { 5 int n, m, op, t, sum = 0; 6 scanf("%d%d", &n, &m); 7 for (int i = 0; i < n; i++){ 8 scanf("%d", &x[i]); 9 sum = add(sum, x[i]); 10 x[i] = -x[i]; 11 } 12 vector<Poly> v(262144); 13 mulInit(1, n, x, v); 14 Poly q = v[1], p = diff(q); 15 int a = 1, b = 0, c = 0, d = 1, cnt = 0; 16 for (int i = 0; i < m; i++){ 17 scanf("%d", &op); 18 if (op == 1){ 19 scanf("%d", &t); 20 a = add(a, mul(t, c)); 21 b = add(b, mul(t, d)); 22 } 23 else{ swap(a, c); swap(b, d); } 24 if (c){ 25 int t = power(c, MOD - 2); 26 w[i] = mul(mul(a, t), n); 27 k[i] = mul(sub(b, mul(a, mul(d, t))), t); 28 y[cnt++] = mul(d, t); 29 } 30 else{ 31 int t = power(d, MOD - 2); 32 w[i] = mul(add(mul(a, sum), mul(b, n)), t); 33 k[i] = -1; 34 } 35 } 36 mulInit(1, cnt, y, v); 37 getVal(1, cnt, p, v, ans1); 38 getVal(1, cnt, q, v, ans2); 39 for (int i = 0, j = 0; i < m; i++){ 40 if (k[i] == -1)printf("%d\n", w[i]); 41 else{ 42 int t = mul(ans1[j], power(ans2[j], MOD - 2)); 43 printf("%d\n", add(w[i], mul(k[i], t))); 44 j++; 45 } 46 } 47 }