HDU 6900 Residual Polynomial 

题意:

给出一个多项式\(f_1(x) = \sum_{i=0}^na_ix^i\)

对于任意\(i>=2\),满足\(f_i(x) = b_i(f_{i-1}(x))'+c_if_{i-1}(x)\)

要求得到\(f_n(x)\)的各次项系数模\(998244353\)

\(n\le 10^5, 0\leq a_i,b_i,c_i < 998244353\)

题解:

考虑把\(f_1,f_2,\cdots,f_n\)写成\(n\)列,其中\(f_{ij}\)表示\(f_i\)的\(j\)次项的系数:

\[\begin{array}{cccc} f_{1,0} & f_{2,0} & f_{3,0} & \cdots & f_{n0,} \\\ f_{1,1} & f_{2,1} & f_{3,1} & \cdots & f_{n,1}\\\ \vdots & \vdots & \vdots &\ddots & \vdots \\\ f_{1,n} & f_{2,n} & f_{3,n} & \cdots & f_{n,n} \end{array}
\]

其中\(f_{1,i}=a_i\)

考虑类似\(dp\)的状态转移,那么可以发现, 对于\(f_{ij}\)存在两种转移:

\[\begin{cases} f_{i,j}\stackrel{c_{i+1}}{\longrightarrow}f_{i+1,j} & i<n \\\ f_{i,j}\stackrel{j\cdot b_{i+1}}{\longrightarrow} f_{i+1,j-1} & i<n , j>0 \end{cases}
\]

其中箭头表示乘自身然后加到右边

那么如果把转移看作边,可以发现每个状态(除了边界)向右连了一条边,向右上连了一条边

我们来考虑\(f_{1,i}\)对\(f_{n,j}\)的贡献,其中\(i\ge j\),可以发现\(dp\)的转移其实就是一条条从\(f_{1,i}\)到\(f_{n,j}\)的路径,那么显然可以把所有路径单独分开来看,那么\(f_{1,i}\)对\(f_{n,j}\)的贡献为:\(f_{1,i}\cdot \sum (\prod \operatorname{pathvalue})\),也就是从\(f_{1,i}\)到\(f_{n,j}\)的所有可行路径的边权乘积的和

先不考虑第二类转移中\(j\cdot b_{i+1}\)的\(j\),那么对于任何转移\(f_{1,i}\rightarrow f_{n,j}\),其实就是对于每个\(2\le k\le n\),选择\(b_k\)或者\(c_k\),其中\(b_k\)选择\(i-j\)个,\(c_k\)选择\(n-1-(i-j)\)个,乘起来然后再把所有方案加起来

我们令选\(x\)个\(b_k\)和\(n-1-x\)个\(c_k\)的所有方案的和为\(F(x)\),那么\(F(x)\)是可以用分治+\(FFT\)来得到

令\(F(l,r,x)\)表示在区间\([l,r)\)中选\(x\)个\(b_k\)的所有方案的和,那么可以得到\(F(l,r,x)=\sum_{i+j=x}F(l,mid,i)\cdot F(mid,r,j)\),其中\(mid = \lfloor \frac{l+r}2\rfloor\)

再算上之前没考虑的\(j\)的贡献乘积,可以得到\(f_{n,j}=\sum_{i-k=j}F(k)\cdot f_{1,i}\cdot \frac{(i-1)!}{(j-1)!}\)

考虑把数组反向,也就是\(f_{i,j}\)和\(f_{i,n-j}\)互换,那么就可以得到\(f_{n,j} = \sum_{i+k=j}F(k)\cdot f_{1,i}\cdot \frac{j!}{i!} = j!\sum_{i+k=j}F(k)\cdot \frac{f_{1,i}}{i!}\)

那么就可以再做一次\(FFT\)就能得到答案了

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MOD = 998244353;
const int FFTN = 1<<19;
const int MAXN = 2e5+7;
#define poly vector<int>
typedef unsigned long long int ull;
int ksm(int a, int b){
int ret = 1;
while(b){
if(b&1) ret = 1ll * ret * a % MOD;
b >>= 1;
a = 1ll * a * a % MOD;
}
return ret;
}
namespace FFT{
int w[FFTN+5],W[FFTN+5],R[FFTN+5];
void FFTinit(){
W[0]=1;
W[1]=ksm(3,(MOD-1)/FFTN);
for(int i = 2; i <= FFTN; i++) W[i]=1ll*W[i-1]*W[1]%MOD;
}
int FFTinit(int n){
int L=1;
for (;L<=n;L<<=1);
for(int i = 0; i <= L - 1; i++) R[i]=(R[i>>1]>>1)|((i&1)?(L>>1):0);
return L;
}
int A[FFTN+5],B[FFTN+5];
ull p[FFTN+5];
void DFT(int *a,int n){
for(int i = 0; i < n; i++) p[R[i]]=a[i];
for(int d = 1; d < n; d <<= 1){
int len=FFTN/(d<<1);
for(int i = 0, j = 0; i < d; i++, j += len) w[i]=W[j];
for(int i = 0; i < n; i += (d<<1))
for (int j = 0; j < d; j++){
int y=p[i+j+d]*w[j]%MOD;
p[i+j+d]=p[i+j]+MOD-y;
p[i+j]+=y;
}
if (d==1<<15)
for(int i = 0; i < n; i++) p[i]%=MOD;
}
for(int i = 0; i < n; i++) a[i]=p[i]%MOD;
}
void IDFT(int *a,int n){
for(int i = 0; i < n; i++) p[R[i]]=a[i];
for (int d=1;d<n;d<<=1){
int len=FFTN/(d<<1);
for (int i=0,j=FFTN;i<d;i++,j-=len) w[i]=W[j];
for (int i=0;i<n;i+=(d<<1))
for (int j=0;j<d;j++){
int y=p[i+j+d]*w[j]%MOD;
p[i+j+d]=p[i+j]+MOD-y;
p[i+j]+=y;
}
if (d==1<<15)
for(int i = 0; i < n; i++) p[i]%=MOD;
}
int val=ksm(n,MOD-2);
for(int i = 0; i < n; i++) a[i]=p[i]*val%MOD;
}
poly Mul(const poly &a,const poly &b){
int sza=a.size()-1,szb=b.size()-1;
poly ans(sza+szb+1);
if (sza<=30||szb<=30){
for(int i = 0; i <= sza; i++) for(int j = 0; j <= szb; j++)
ans[i+j]=(ans[i+j]+1ll*a[i]*b[j])%MOD;
return ans;
}
int L=FFTinit(sza+szb);
for(int i = 0; i < L; i++) A[i]=(i<=sza?a[i]:0);
for(int i = 0; i < L; i++) B[i]=(i<=szb?b[i]:0);
DFT(A,L); DFT(B,L);
for(int i = 0; i < L; i++) A[i]=1ll*A[i]*B[i]%MOD;
IDFT(A,L);
for(int i = 0; i <= sza + szb; i++) ans[i]=A[i];
return ans;
}
}
int fac[MAXN], rfac[MAXN], inv[MAXN];
poly divide(int l, int r, vector<int> &B, vector<int> &C){ return l + 1 == r ? poly({C[l],B[l]}) : FFT::Mul(divide(l,(l+r)>>1,B,C), divide((l+r)>>1,r,B,C)); }
void solve(){
int n; scanf("%d",&n);
vector<int> A(n+1), B(n-1), C(n-1);
for(int &x : A) scanf("%d",&x);
for(int &x : B) scanf("%d",&x);
for(int &x : C) scanf("%d",&x);
poly f = divide(0,n-1,B,C);
reverse(A.begin(),A.end());
for(int i = 0; i <= n; i++) A[i] = 1ll * A[i] * fac[n-i] % MOD;
poly W = FFT::Mul(A,f);
for(int i = 0; i <= n; i++) W[i] = 1ll * W[i] * rfac[n-i] % MOD;
for(int i = n; i >= 0; i--) printf("%d%c",W[i]," \n"[!i]);
}
int main(){
fac[0] = rfac[0] = inv[1] = 1;
for(int i = 1; i < MAXN; i++) fac[i] = 1ll * fac[i-1] * i % MOD;
for(int i = 2; i < MAXN; i++) inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
for(int i = 1; i < MAXN; i++) rfac[i] = 1ll * rfac[i-1] * inv[i] % MOD;
FFT::FFTinit();
int tt; for(scanf("%d",&tt); tt--; solve());
return 0;
}

HDU 6900 Residual Polynomial【分治 NTT】的更多相关文章

  1. HDU 5552 Bus Routes(2015合肥现场赛A,计数,分治NTT)

    题意  给定n个点,任意两点之间可以不连边也可以连边.如果连边的话可以染上m种颜色. 求最后形成的图,是一个带环连通图的方案数. 首先答案是n个点的图减去n个点能形成的树. n个点能形成的树的方案数比 ...

  2. HDU 6270 Marriage (2017 CCPC 杭州赛区 G题,生成函数 + 容斥 + 分治NTT)

    题目链接  2017 CCPC Hangzhou Problem G 题意描述很清晰. 考虑每个家庭有且仅有$k$对近亲的方案数: $C(a, k) * C(b, k) * k!$ 那么如果在第$1$ ...

  3. HDU 5279 YJC plays Minecraft (分治NTT优化DP)

    题目传送门 题目大意:有$n$个小岛,每个小岛上有$a_{i}$个城市,同一个小岛上的城市互相连接形成一个完全图,第$i$个小岛的第$a_{i}$个城市和第$i+1$个小岛的第$1$个城市连接,特别地 ...

  4. HDU 5322 Hope (分治NTT优化DP)

    题面传送门 题目大意: 假设现在有一个排列,每个数和在它右面第一个比它大的数连一条无向边,会形成很多联通块. 定义一个联通块的权值为:联通块内元素数量的平方. 定义一个排列的权值为:每个联通块的权值之 ...

  5. hdu 5830 FFT + cdq分治

    Shell Necklace Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  6. hdu 4812 DTree (点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total S ...

  7. #565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)

    题面 戳这里,题意简单易懂. 题解 首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和) ...

  8. LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)

    考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...

  9. 【BZOJ-3456】城市规划 CDQ分治 + NTT

    题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...

随机推荐

  1. COW技术重置虚拟机

    最近使用COW技术做虚拟机重置,结果成功了,特地来给大家分享一下这次的成果! 文章目录 一.COW技术是什么? 二.重置虚拟机步骤 总结 往期杂文 一.COW技术是什么? Copy On Write, ...

  2. 安装weblogic 11g

    参考 https://blog.csdn.net/z69183787/article/details/38401013 https://blog.csdn.net/wjf8882300/article ...

  3. 2020周阳SpringCloud完整版笔记--一

    微服务架构入门 微服务 的概念最早产生于Martin Fowler在2014年的一篇论文中. 微服务架构是一种架构模式,他提倡将单一应用程序划分成一组小的服务,服务与服务之间互相协调.相互配合,为用户 ...

  4. 基于Python实现的系统SLA可用性统计

    基于Python实现的系统SLA可用性统计 1. 介绍 SLA是Service Level Agreement的英文缩写,也叫服务质量协议.根据SRE Google运维解密一书中的定义: SLA是服务 ...

  5. mysql中的基本注入函数

    1. 常见数据库注入函数: MYSQL: and length((user))>10 ACCESS: and (select count() from MSysAccessObject)> ...

  6. 【Linux】自建回收站

    linux rm命令是即刻删除的,而且挺多人喜欢加上-f强制命令,更暴力的是删除文件夹直接 rm -rf ,这样子代表你执行完后,就完全被干掉了. 还是推荐在linux下设置回收站,写一个shell脚 ...

  7. 修改conda和pip源

    修改conda源为中科大源 Windows修改C:\Users\user(user替换为当前登陆系统的用户)目录下的.condarc文件 Linux修改家目录下的.condarc文件 channels ...

  8. 把vscode打造成技术写作神器

    作为技术开发,大家平时肯定需要记录技术笔记.甚至有的同学还开通可自己的技术博客或者技术公众号进行创作. 这个时候有套趁手的写作工具尤为重要,节省下时间好好休息一下,对于咱们程序员来说更加重要.因为最近 ...

  9. ALV中layout布局控制详解

    参数的结构为SLIS_LAYOUT_ALV.结构中比较常用的字段如下: no_colhead      隐藏列标题          值为X或空 no_hotspot     headings不作为热 ...

  10. JMM在X86下的原理与实现

    JMM在X86下的原理与实现 Java的happen-before模型 众所周知 Java有一个happen-before模型,可以帮助程序员隔离各个平台多线程并发的复杂性,只要Java程序员遵守ha ...