終於把多項式差不多弄完了,可以找個機會在退役前把多項式整理封裝弄好,也算是留下了一點東西吧(嘿嘿。
這一部分實例的代碼是用 封裝好的,這篇博客先提一下前置:
首先是可能需要用到的定義,都是比較基礎的數論知識,不贅述了:
#define Polynomial vector<int>
//封裝多項式爲 std::vector,方便resize等操作
void print(Polynomial &a,int len){for(int i=0;i<len;i++)printf("%d ",a[i]);}
const int mod=998244353,mod_g=3,img=86583718;
//mod爲多項式係數的取模值,mod_g是它的原根,img爲在模意義下的虛部,只有多項式三角函數會遇到。
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void exgcd(int a,int b,int &x,int &y){
if(!b){x=1;y=0;return;}
exgcd(b,a%b,y,x);y-=x*(a/b);
}
//gcd,exgcd只有在開根的時候會用到
int power(int a,int b)
{int ans=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;}
#define Inv(x) power(x,mod-2)
然後是核心的快速數論變換 ,相關請看【求多項式卷積的變換】:
Polynomial R;
inline int Binary_Rounding(const int &n)
{int len=1;for(;len<n;len<<=1);return len;}
//二進制向上取整,爲方便NTT變換準備。
inline int Prepare_Transformation(int n){
int L=0,len;for(len=1;len<n;len<<=1)L++;R.clear();R.resize(len);
for(int i=0;i<len;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
return len;
}
//預處理R數組,準備變換,在每次NTT之前理論都要調用此函數。
void NTT(Polynomial &a,int f){
int n=a.size();
for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1)
for(int j=0,gn=power(mod_g,(mod-1)/(i<<1));j<n;j+=(i<<1))
for(int k=0,g=1,x,y;k<i;k++,g=1ll*g*gn%mod)
x=a[j+k],y=1ll*g*a[i+j+k]%mod,
a[j+k]=(x+y)%mod,a[i+j+k]=(x-y+mod)%mod;
if(f==-1){
reverse(a.begin()+1,a.end());
int inv=Inv(n);
for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
}
}
在掌握上面簡單知識後,就可以進行多項式的入門了,我差不多按照學習的拓撲序給出下面的目錄,也分開記錄一下自己的模板:
對了,還是建議用 的,用數組的話,到時候對於臨時數組的清空問題會讓你懷疑人生的!!
-
多項式全家桶(一):多項式的加,減,卷積
- 多項式加,減單項式;
- 多項式卷積單項式;
- 多項式加,減多項式;
- 多項式卷積多項式;
- 多項式除法和取模。
-
多項式全家桶(二):多項式的逆,導,積
- 多項式求逆;
- 多項式求導;
- 多項式求積;
- 多項式複合逆。
-
多項式全家桶(三):多項式的 ,
- 多項式的;
- 多項式的。
-
多項式全家桶(四):多項式快速冪,開方
- 多項式快速冪;
- 多項式開方;
- 多項式開高次方。
-
多項式全家桶(五):多項式三角函數,反三角函數
- 多項式;
- 多項式;
- 多項式;
- 多項式。