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. linux下如何看系统日志及Out Of Memery

    1.一个Out Of Memery(OOM)导致的崩溃. linux系统经常会由于资源的问题导致自己的程序莫名被杀掉,可以从linux的系统日志中找到答案: vi /var/log/message - ...

  2. linux mysql source 导入大文件报错解决办法

    找到mysql的配置文件目录 my.cnf interactive_timeout = 120wait_timeout = 120max_allowed_packet = 500M 在导入过程中可能会 ...

  3. tomcat版本号修改已dwr配置错误安全漏洞整改

    1.tomcat版本信息泄露修改方法:tomcat6是在tomcat/lib 下使用jar xf catalina.jar 解压这个jar包会得到两个目录:META-INF和org其中org\apac ...

  4. 【Redis3.0.x】实战案例

    Redis3.0.x 实战案例 简介 <Redis实战>的学习笔记和总结. 书籍链接 初识 Redis Redis 简介 Redis 是一个速度非常快的键值对存储数据库,它可以存储键和五种 ...

  5. 当Django设置DEBUG为False时,发现admin和html的静态资源文件加载失败的解决办法

    当Django设置DEBUG为False时,发现admin和html的静态资源文件加载失败,折腾一段时间终于找到解决办法: 1.先在setting文件增加BASE_DIR(项目的路径) BASE_DI ...

  6. 【Linux】1、命令行及命令参数

    命令行及命令参数 文章目录 命令行及命令参数 1.命令行提示符 2.命令和命令参数 简单的命令 date ls 命令参数 短参数(一个字母) 长参数(多个字母) 参数的值 其它参数 3.小结 4.参考 ...

  7. Azure App object和Service Principal

    为了把Identity(身份)和Access Management function(访问管理功能)委派给Azure AD,必须向Azure AD tenant注册应用程序.使用Azure AD注册应 ...

  8. 图解 | 原来这就是TCP

    你是一台电脑,你的名字叫 A 经过<图解 | 原来这就是网络>这篇文章中的一番折腾,只要你知道另一位伙伴 B 的 IP 地址,且你们之间的网络是通的,无论多远,你都可以将一个数据包发送给你 ...

  9. winform 添加背景图 闪屏问题解决

    winform中只要添加了背景图片资源,窗体加载显示的时候就会出现不停的闪屏操作,网上找了很多方法,效果都不明显: 然后自己观察和思路:看窗体的加载过程,当有背景图的时候,首先出来的是背景图,之后背景 ...

  10. 一步步使用SpringBoot结合Vue实现登录和用户管理功能

    前后端分离开发是当今开发的主流.本篇文章从零开始,一步步使用SpringBoot结合Vue来实现日常开发中最常见的登录功能,以及登录之后对用户的管理功能.通过这个例子,可以快速入门SpringBoot ...