题解:CF1967C Fenwick Tree
我们充分发扬人类智慧
题意
我们定义操作为:
给出
更改关系
由于
我们列举一下影响关系,易于知道这些关系简化成祖先到子孙的关系可以得到一棵树状数组。
贡献
对于祖先关系的两点,我们发现同层的两个点对共同祖先的更改可以按同类处理,我们可以考虑操作时
- 操作一次,
a_2 共加上一次a_1 ,a_4 加上一次a_1 。 - 操作两次,
a_2 共加上2 次a_1 ,a_4 加上3 次a_1 。 - 操作三次,
a_2 共加上3 次a_1 ,a_4 加上6 次a_1 。
由此我们猜测当
接下来证明:
- 当
t = 1 时,b_j 加了k = \frac{(k +1 - 1)!}{1! \cdot (k - 1)!} 次a_i ,符合条件; - 若
t = r 时成立,当t = r + 1 时,加上的倍数为:
因为
故
证毕。
3. 反推
我们易得可以从前往后遍历,遍历到
通过类似树状数组的修改方法,可以得到一个
4. 上代码
#include<cstdio>
using namespace std;
int n,m,k,b[200009],dt[29],inv[29];
const int mod = 998244353;
int main(){
scanf("%d",&m);
while(m--){
scanf("%d %d",&n,&k);
dt[0] = 1;
for(int i = 1; i <= 20; i ++){
inv[i] = (i == 1) ? 1 : 1ll * (mod - mod / i) * inv[mod % i] % mod;
dt[i] = 1ll * dt[i - 1] * (k + i - 1) % mod;
dt[i] = 1ll * dt[i] * inv[i] % mod;
}
for(int i = 1; i <= n; i ++){
scanf("%d",&b[i]);
}
for(int i = 1; i <= n; i ++){
int o = i;
for(int j = 1; o + (o & (-o)) <= n; j ++){
o += o & (-o);
b[o] = (b[o] - 1ll * b[i] * dt[j] % mod + mod) % mod;
//printf("%d %d %d\n",i,o,b[o]);
}
}
for(int i = 1; i <= n; i ++){
printf("%d ",b[i]);
}
puts("");
//return 0;
}
return 0;
}