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 }

 

posted @ 2018-03-14 20:35  zbh2047  阅读(439)  评论(1编辑  收藏  举报