题目
给定长为n(n<=2e5)的序列a,第i个数ai(0<=ai<998244353)
求序列f,满足式子如下:
思路来源
jiangly代码/力扣群友tdzl2003/propane/自己的乱搞

题解
分治NTT,考虑[l,mid]对[mid+1,r]的贡献,
但是,手玩一下就会发现有个问题
举个例子,
1. [l,mid]=[0,1],[mid+1,r]=[2,3],那么右半边f2会加上f0*(f0+f1)+f1*f0,贡献完整
2. [l,mid]=[5,6],[mid+1,r]=[7,8],那么右半边f7会加上f5*(f0+f1)+f6*f0
相当于只有一半贡献,比如有f5*f0,没有f0*f5,
因为考虑f0所在区间对右的贡献时,f5还没算出来
对于第二种情况,贡献就需要乘以2
这两种情况会混在一起导致很难算么,答案是不会的
考虑第一次出现贡献完整,不需要*2的项时,
左边两个下标最小,右边下标最大,也就是l+l=r-1,满足2*l<r
由于分治NTT是分治的完整的2的幂次的区间,左右半段等长,
观察不难发现(jiangly代码告诉我们)只有l=0时,才会出现2*l<r
所以,分类讨论两种情况即可
Bonus
官方题解/群友给出了全在线卷积/半在线卷积的解法,更好理解,
一边卷积求第i项,一边维护卷积的前缀和
大概看了看是构造出了一个矩阵,
数字表示该数加入的时候算哪些矩阵,
每个矩阵对应一个边长规模的卷积

从而保证任何时刻均摊都是n(logn)^2,可以考虑以后整理个板子(咕)……
代码1(参考)
时间大概是代码2的一半
l=r处求f[l]的值,卷积的前缀和也是在此处算的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long
#define ull unsigned ll
const int N = 1<<20, P = 998244353;
const int Primitive_root = 3;
struct Z{
int x;
Z(const int _x=0):x(_x){}
Z operator +(const Z &r)const{ return x+r.x<P?x+r.x:x+r.x-P;}
Z operator -(const Z &r)const{ return x<r.x?x-r.x+P:x-r.x;}
Z operator -()const{ return x?P-x:0;}
Z operator *(const Z &r)const{ return static_cast<ull>(x)*r.x%P;}
Z operator +=(const Z &r){ return x=x+r.x<P?x+r.x:x+r.x-P, *this;}
Z operator -=(const Z &r){ return x=x<r.x?x-r.x+P:x-r.x, *this;}
Z operator *=(const Z &r){ return x=static_cast<ull>(x)*r.x%P, *this;}
friend Z Pow(Z, int);
pair<Z,Z> Mul(pair<Z,Z> x, pair<Z,Z> y, Z f)const{
return make_pair(
x.first*y.first+x.second*y.second*f,
x.second*y.first+x.first*y.second
);
}
};
Z Pow(Z x, int y=P-2){

博客围绕给定长为n的序列a求序列f的问题展开。采用分治NTT方法,考虑[l,mid]对[mid+1,r]的贡献,分析了贡献完整和只有一半贡献的情况并分类讨论。此外,还提及官方和群友给出的全在线卷积/半在线卷积解法,最后给出参考代码和乱搞代码。
最低0.47元/天 解锁文章
2474

被折叠的 条评论
为什么被折叠?



