【学习总结】生成函数题目,多项式模板

这篇博客总结了多项式技巧,重点介绍了牛顿迭代(泰勒展开)及其在模xn意义下的应用。博主强调泰勒展开在多项式运算中的重要作用,并提供了例题解析,如【BZOJ3625】小朋友和二叉树、bzoj 3684 大朋友和多叉树,以及多项式模板的应用。同时,还讨论了复合逆和拉格朗日反演,提醒读者注意多项式求逆的条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习资料:
王乐平、策爷冬令营讲义。

多项式技巧

牛顿迭代(泰勒展开)

很多时候推式子就是取对数、积分,exp和泰勒展开的结合
泰勒展开在mod xn意义下只需要保留前n项,性质非常优美。
而插值,对于一个k次的多项式,必须要k + 1个值的代入,如果只求该多项式的前n项,也不能只用
n + 1个点代入

这是一篇非常好的博客。特别是把所有多项式操作都用泰勒展开推导,以后就不用再死记,也不用担心推错了!from yyb

复合逆

拉格朗日反演
在这里插入图片描述

注意当f(x)本身不存在逆元的时候,可以求f(x) / x的逆元
否则(x / f(x))n 的第n - 1
项为0

例题

直接推生成函数

【BZOJ3625】小朋友和二叉树

from cz_xuyixuan
注意这道题是普通生成函数,不是指数型生成函数

代码只有main函数,多项式模板在下面

int n,m;
vector <int> fact,inv_fact;
vector <int> f,g,h,tmp;

void pre_calc(){
   
 // g[0] = 1;
  rep(i,0,m){
   
   // g[i] = mul(g[i],inv_fact[i]);
    sub(f[i],mul(g[i],4));
 //   cout<<f[i]<<" ";
  }
  f[0] = 1;
 // cout<<endl;
  f = sqrt(f);
  add(f[0],1);
  f = inverse(f);
  rep(i,0,m) f[i] = mul(f[i],2);
}

int main(){
   
  scanf("%d %d",&n,&m);
  f.resize(m + 1) , g.resize(m + 1);
  rep(i,1,n){
   
    int x;
    scanf("%d",&x);
    if ( x <= m ) g[x]++;
  }
  pre_calc();
  rep(i,1,m){
   
   // f[i] = mul(f[i],fact[i]);
    printf("%d\n",f[i]);
  }
}
bzoj 3684 大朋友和多叉树

复合逆裸题。
注意F(x) / x才可以求逆

int n,m;
poly fact,inv_fact;
poly f,g,h,tmp;

void pre_calc(){
   
  add(g[0],1);
  g = inverse(g);

  g = power(g,n);
  int ans = mul(power(n,mod - 2),g[n - 1]);

  cout<<ans<<endl;
}
int main(){
   
 scanf("%d %d",&n,&m);
 f.resize(n + 1) , g.resize(n + 1);
 rep(i,1,m){
   
  int x;
  scanf("%d",&x);
  g[x - 1] = mod - 1;
 }
 pre_calc();
}

多项式模板

注意事项:
求导和积分多项式的次数变化
开根号如果常数项不为完全平方数,需要用二次剩余开根号的模板。详见这位大佬
求逆常数项不能为0 , 否则不存在逆元
special thanks to wxh010910

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const int maxn = 200020;

typedef vector <int> poly;
const int mod = 950009857;

//NOTES: 任意乘法需要用mul,或者强制用long long。
//注意取模
//====================================basic operation===============================
inline void add(int &x, int y) {
   
  x += y;
  if (x >= mod) {
   
    x -= mod;
  }
}

inline void sub(int &x, int y) {
   
  x -= y;
  if (x < 0) {
   
    x += mod;
  }
}

inline int mul(int x, int y) {
   
  return (int) ((long long) x * y % mod);
}

inline int power(int x, int y) {
   
  int res = 1;
  while (y) {
   
    if (y & 1) {
   
      res = mul(res, x);
    }
    x = mul(x, x);
    y >>= 1;
  }
  return res;
}

inline int inv(int a) {
   
  int b = mod, u = 0, v = 1;
  while (a) {
   
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  if (u < 0) {
   
    u += mod;
  }
  return u;
}
//=============
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值