• 鬼畜的多项式


    写点做多项式笔记以及遇到的各种蛋疼的东西....(不懂可以Q我辣我十分愿意!

    (picks博客已经成为中国多项式入门到精通的经典教程辣!详见:http://picks.logdown.com/archives

    多项式乘法:

    裸的fft= =复数搞搞

    数论变换的多项式乘法:

    对于一些要对系数取模而取的模十分鬼畜即满足存在$k$,使得$2^k | (P-1) 且 2^k > n$时那么可以用一个$P$的原根代替复数根,即用$g^{frac{P-1}{m}}$代替fft里的单位根$omega ^{ frac{2 pi i}{m} }$。其逆为$n^{-1} g^{-frac{P-1}{m}}$。容易证明这是正确的。(可以照着算导对单位根的所需要性质然后来证明)

    多项式求逆:

    这个求逆指的是对一个$mod$特定次数的$x$求逆,例如求$A(x)$在模$x^n$下的逆,即求一个$B(x)$使得$A(x)B(x) equiv 1 pmod{x^n}$,这个用倍增的思想容易得到

    $$ B_{n}(x) equiv B_{ left lceil frac{n}{2} ight ceil } left( 2 - A(x)B_{ left lceil frac{n}{2} ight ceil } ight) pmod{x^n} $$

    $B_{n}(x)$指的是在模$x^n$下的$A$的逆

    这里一定注意在码的时候,右式得到的次数界应该大于等于$n+n$(在这里大于的部分被模掉了!)的啊...不要以为是$n+left lceil frac{n}{2} ight ceil +1$啊555,在这里wa了好多发啊QAQ

    多项式除法+取模:

    指的是给出$A(x), B(x)$求$A(x) = B(x)C(x) + D(x)$,其中满足$deg(A)=deg(B)+deg(C), deg(D)<deg(B)$

    这里需要用点技巧orz如果能想到翻转多项式那么这题就好做了orz令$F^{R}(x)$表示将多项式$F(x)$系数前后翻转后的多项式,即$F^{R}(x) = x^{deg(F)} F(frac{1}{x})$。那么我们将$frac{1}{x}$先带入$A(x) = B(x)C(x) + D(x)$并乘上一个$x^{deg(A)}$最后化简能得到就能得到

    $$A^R(x) equiv B^R(x)C^R(x) pmod{x^{deg(A)-deg(B)}}$$

    取模也相应解决了

    多项式开根:

    指的是在模$x^n$的意义下给出$A(x)$,求$sqrt{A(x)}$。那么能开根的条件就是$A(x)$的最低次是2的倍数且系数能被开根。

    如果想到倍增这个问题也是很好解决的...最终得到

    $$A equiv left( 2^{-1} A_{ left lceil frac{n}{2} ight ceil } + 2^{-1} A A_{ left lceil frac{n}{2} ight ceil }^{-1} ight)^2 pmod{x^n}$$

    下标的意义同求逆那里。($A_{t}$表示$A_{t}^2 equiv A pmod{x^t}$

    要注意的和求逆那里一样,右式次数界同样是大于等于$n+n$且求逆的时候是取模$x^n$下的逆,因为$A_{ left lceil frac{n}{2} ight ceil }^{-1}$的次数界可能为$n$。

    对应的例题看picks博客辣= =

    多项式求逆:【BZOJ】3456: 城市规划

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=130050, fN=N<<2;
    const ll mo=1004535809;
    ll G[35], nG[35];
    int rev[fN];
    ll ipow(ll a, int b) { ll x=1; for(; b; b>>=1, (a*=a)%=mo) if(b&1) (x*=a)%=mo; return x; }
    void fft(ll *a, int n, int f) {
    	for(int i=0; i<n; ++i) if(i<rev[i]) swap(a[i], a[rev[i]]);
    	int now=-1;
    	for(int m=2; m<=n; m<<=1) {
    		int mid=m>>1; ++now;
    		ll wn=G[now]; if(f) wn=nG[now];
    		for(int i=0; i<n; i+=m) {
    			ll w=1;
    			for(int j=0; j<mid; ++j) {
    				ll u=a[i+j], v=a[i+j+mid]*w%mo;
    				a[i+j]=(u+v)%mo;
    				a[i+j+mid]=(u-v+mo)%mo;
    				(w*=wn)%=mo;
    			}
    		}
    	}
    }
    ll tmp[fN];
    void getinv(ll *A, ll *B, int n) {
    	if(n==1) { B[0]=ipow(A[0], mo-2); return; }
    	getinv(A, B, (n+1)>>1);
    	int len=1, bl=-1, nn=(n<<1)-1;
    	for(; len<nn; len<<=1, ++bl);
    	for(int i=1; i<len; ++i) rev[i]=(rev[i>>1]>>1)|(((ll)i&1)<<bl);
    	for(int i=0; i<n; ++i) tmp[i]=A[i]; for(int i=n; i<len; ++i) tmp[i]=0;
    	fft(tmp, len, 0); fft(B, len, 0);
    	for(int i=0; i<len; ++i) B[i]=B[i]*((2-tmp[i]*B[i]%mo+mo)%mo)%mo;
    	fft(B, len, 1); ll nN=ipow(len, mo-2);
    	for(int i=0; i<n; ++i) (B[i]*=nN)%=mo; for(int i=n; i<len; ++i) B[i]=0;
    }
    ll ni[N], p[N], A[fN], B[fN], nA[fN];
    int main() {
    	int n;
    	scanf("%d", &n);
    	if(n<=2) { puts("1"); return 0; }
    
    	int len=1, bl=-1, nn=((n+1)<<1)-1;
    	for(; len<nn; len<<=1, ++bl);
    	G[bl]=ipow(3, (mo-1)/len); nG[bl]=ipow(G[bl], mo-2);
    	for(int i=bl-1; i>=0; --i) G[i]=G[i+1]*G[i+1]%mo, nG[i]=nG[i+1]*nG[i+1]%mo;
    	ni[1]=1; p[1]=1; p[0]=1;
    	for(int i=2; i<=n; ++i) ni[i]=((-(mo/i)*ni[mo%i])%mo+mo)%mo;
    	for(int i=2; i<=n; ++i) p[i]=p[i-1]*ni[i]%mo;
    	A[0]=1, B[0]=0;
    	ll last=1, C=1;
    	for(int i=1; i<=n; ++i) A[i]=last*p[i]%mo, B[i]=last*p[i-1]%mo, last=last*((C<<=1)%=mo)%mo;
    	getinv(A, nA, n+1);
    	for(int i=1; i<len; ++i) rev[i]=(rev[i>>1]>>1)|(((ll)i&1)<<bl);
    	fft(nA, len, 0); fft(B, len, 0);
    	for(int i=0; i<len; ++i) (B[i]*=nA[i])%=mo;
    	fft(B, len, 1); ll nN=ipow(len, mo-2);
    	for(int i=0; i<=n; ++i) (B[i]*=nN)%=mo;
    	ll pp=1;
    	for(int i=2; i<=n; ++i) (pp*=(i-1))%=mo, (B[i]*=pp)%=mo;
    	printf("%lld
    ", B[n]);
    	return 0;
    }
    

      

    多项式除法+取模:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define CC(a, b) memset(a, 0, sizeof(int)*(b))
    const int N=130005, fN=N<<2, BN=30, mo=1004535809, n_G=3;
    int G[BN], nG[BN], rev[fN];
    int ipow(int a, int b) { int x=1; for(; b; b>>=1, a=(ll)a*a%mo) if(b&1) x=(ll)x*a%mo; return x; }
    void P(int *a, int n) { for(int i=n-1; i>=0; --i) printf("%d ", a[i]); puts(""); }
    void fft_init() {
    	G[21]=ipow(n_G, (mo-1)/(1<<21)); nG[21]=ipow(G[21], mo-2);
    	for(int i=20; i; --i) G[i]=(ll)G[i+1]*G[i+1]%mo, nG[i]=(ll)nG[i+1]*nG[i+1]%mo;
    }
    int getlen(int n) {
    	int len=1, b=-1;
    	for(; len<n; len<<=1, ++b);
    	for(int i=0; i<len; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<b);
    	return len;
    }
    void fft(int *a, int n, int f) {
    	for(int i=0; i<n; ++i) if(i<rev[i]) swap(a[i], a[rev[i]]);
    	for(int m=2, now=1; m<=n; m<<=1, ++now) {
    		int mid=m>>1, wn=G[now], w, u, v; if(f) wn=nG[now];
    		for(int i=0; i<n; i+=m) {
    			w=1;
    			for(int j=0; j<mid; ++j) {
    				u=a[i+j], v=(ll)a[i+j+mid]*w%mo;
    				a[i+j]=(u+v)%mo; a[i+j+mid]=(u-v+mo)%mo;
    				w=(ll)w*wn%mo;
    			}
    		}
    	}
    }
    void mul(int *a, int *b, int *c, int n, int m, int &k) {
    	int len=getlen((n+m)-1), nlen=ipow(len, mo-2);
    	static int x[fN], y[fN];
    	for(int i=0; i<n; ++i) x[i]=a[i];
    	for(int i=0; i<m; ++i) y[i]=b[i];
    	fft(x, len, 0); fft(y, len, 0);
    	for(int i=0; i<len; ++i) y[i]=(ll)y[i]*x[i]%mo;
    	fft(y, len, 1);
    	k=n+m-1;
    	for(int i=0; i<k; ++i) c[i]=(ll)y[i]*nlen%mo;
    	while(k && c[k-1]==0) --k;
    	CC(x, len); CC(y, len);
    }
    void getinv(int *a, int *b, int n) {
    	if(n==1) { b[0]=ipow(a[0], mo-2); return; }
    	getinv(a, b, (n+1)>>1);
    	static int c[N], d[N];
    	memcpy(c, a, sizeof(int)*(n)); memcpy(d, b, sizeof(int)*((n+1)>>1));
    	int len=getlen(n+n-1), nlen=ipow(len, mo-2);
    	fft(c, len, 0); fft(d, len, 0);
    	for(int i=0; i<len; ++i) d[i]=(ll)d[i]*(2-(ll)d[i]*c[i]%mo+mo)%mo;
    	fft(d, len, 1);
    	for(int i=0; i<n; ++i) b[i]=(ll)d[i]*nlen%mo;
    	CC(c, len); CC(d, len);
    }
    void div(int *a, int *b, int *c, int n, int m, int &k) {
    	static int ar[fN], br[fN], nbr[fN];
    	if(n<m) { k=1; return; }
    	for(int i=0; i<n; ++i) ar[i]=a[n-i-1]; 
    	for(int i=0; i<m; ++i) br[i]=b[m-i-1]; 
    	k=n-m+1;
    	getinv(br, nbr, k);
    	int len=getlen(n+n-1), nlen=ipow(len, mo-2);
    	fft(ar, len, 0); fft(nbr, len, 0);
    	for(int i=0; i<len; ++i) nbr[i]=(ll)ar[i]*nbr[i]%mo;
    	fft(nbr, len, 1);
    	for(int i=0; i<k; ++i) c[i]=(ll)nbr[k-i-1]*nlen%mo;
    	while(k && c[k-1]==0) --k;
    	CC(ar, len); CC(br, len); CC(nbr, len);
    }
    void getmod(int *a, int *b, int *r, int n, int m, int &k) {
    	static int c[fN], t[fN], clen;
    	div(a, b, c, n, m, clen);
    	int len=getlen((clen+m)-1), nlen=ipow(len, mo-2);
    	for(int i=0; i<m; ++i) t[i]=b[i];
    	fft(t, len, 0); fft(c, len, 0);
    	for(int i=0; i<len; ++i) c[i]=(ll)c[i]*t[i]%mo;
    	fft(c, len, 1);
    	for(int i=0; i<n; ++i) r[i]=(a[i]-(ll)c[i]*nlen%mo+mo)%mo;
    	k=n; while(k && r[k-1]==0) --k;
    	CC(c, len); CC(t, len); 
    }
    int main() {
    	fft_init();
    
    	return 0;
    }
    

      

    多项式开根:【CF】438E. The Child and Binary Tree

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=(1e5+10)*4, mo=998244353;
    int two, G[30], nG[30], rev[N];
    int ipow(int a, int b) { int x=1; for(; b; b>>=1, a=(ll)a*a%mo) if(b&1) x=(ll)x*a%mo; return x; }
    void fft_init() {
    	two=ipow(2, mo-2); G[23]=ipow(3, (mo-1)/(1<<23)); nG[23]=ipow(G[23], mo-2);
    	for(int i=22; i; --i) G[i]=(ll)G[i+1]*G[i+1]%mo, nG[i]=(ll)nG[i+1]*nG[i+1]%mo;
    }
    int getlen(int n) {
    	int len=1, bl=-1;
    	for(; len<n; len<<=1, ++bl);
    	for(int i=1; i<len; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<bl);
    	return len;
    }
    void fft(int *a, int n, int f) {
    	for(int i=0; i<n; ++i) if(i<rev[i]) swap(a[i], a[rev[i]]);
    	for(int m=2, now=1; m<=n; m<<=1, ++now) {
    		int mid=m>>1, w=1, wn=G[now], u, v; if(f) wn=nG[now];
    		for(int i=0; i<n; i+=m, w=1) 
    			for(int j=0; j<mid; ++j) {
    				u=a[i+j], v=(ll)a[i+j+mid]*w%mo;
    				a[i+j]=(u+v)%mo; a[i+j+mid]=(u-v+mo)%mo; w=(ll)w*wn%mo;
    			}
    	}
    }
    void getinv(int *a, int *b, int n) {
    	if(n==1) { b[0]=ipow(a[0], mo-2); return; }
    	getinv(a, b, (n+1)>>1);
    	static int c[N], d[N];
    	memcpy(c, a, sizeof(int)*(n)); memcpy(d, b, sizeof(int)*((n+1)>>1));
    	int len=getlen(n+n-1), nlen=ipow(len, mo-2);
    	fft(c, len, 0); fft(d, len, 0);
    	for(int i=0; i<len; ++i) d[i]=(ll)d[i]*(2-(ll)d[i]*c[i]%mo+mo)%mo;
    	fft(d, len, 1);
    	for(int i=0; i<n; ++i) b[i]=(ll)d[i]*nlen%mo;
    	memset(c, 0, sizeof(int)*(len)); memset(d, 0, sizeof(int)*(len));
    }
    void getroot(int *a, int *b, int n) {
    	if(n==1) { b[0]=sqrt(a[0]); return; }
    	getroot(a, b, (n+1)>>1);
    	static int c[N], d[N];
    	memcpy(c, a, sizeof(int)*(n));
    	getinv(b, d, n);
    	int len=getlen(n+n-1), nlen=ipow(len, mo-2);
    	fft(c, len, 0); fft(d, len, 0);
    	for(int i=0; i<len; ++i) d[i]=(ll)c[i]*d[i]%mo;
    	fft(d, len, 1);
    	for(int i=0; i<n; ++i) b[i]=(ll)two*((b[i]+(ll)d[i]*nlen%mo)%mo)%mo;
    	memset(d, 0, sizeof(int)*(len)); memset(c, 0, sizeof(int)*(len));
    }
    int a[N], b[N];
    int main() {
    	fft_init();
    	int m, n; scanf("%d%d", &n, &m);
    	for(int i=0; i<n; ++i) { int x; scanf("%d", &x); if(x<=m) a[x]=mo-4; }
    	a[0]=1;
    	getroot(a, b, m+1);
    	b[0]=(b[0]+1)%mo;
    	getinv(b, a, m+1);
    	for(int i=1; i<=m; ++i) printf("%d
    ", (a[i]<<1)%mo);
    	return 0;
    }
    

      

  • 相关阅读:
    Java:线程的六种状态及转化
    Java:多线程概述与创建方式
    小白学Java:RandomAccessFile
    如何用IDEA开启断言
    如何通过IDEA添加serialVersionUID
    小白学Java:I/O流
    更改IDEA相对路径
    小白学Java:File类
    小白学Java:内部类
    Leetcode数组题*3
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4365425.html
Copyright © 2020-2023  润新知