常数变易法的证明/P6613 题解

· · 题解

可能更好的阅读体验
题解区的很多大佬都是强解微分方程的,但常数变易法蒟蒻对此有许多不解。
因此蒟蒻在此给出本题常数变易法的证明。

一阶线性微分方程的常数变易法

这里有基础的大佬可以直接跳过。

让我们先考虑 一阶齐次线性微分方程:

y'=P(x)y

显然,我们已经知道了 (\ln y)'=\dfrac{y'}{y},因此该方程化为

(\ln y)'=P(x) \ln y=\int P(x)\mathrm{d}x+\ln C y=Ce^{\int P(x)\mathrm{d}x}

其中 C 为常数,由实际情况决定。

这个过程被称为分离变量法,相当地简单。

但对于一般的 一阶线性微分方程,多了一个与 y 无关的 Q(x),难度就直线飙升:

y'=P(x)y+Q(x)

为求出该方程的通解,拉格朗日花了整整 11 年的时间(在此佩服大佬的毅力),
最后发现,如果把 y 拆开,变为 y=uv,方程就可解了:

u'v+uv'=P(x)uv+Q(x) u'v+u(v'-P(x)v)=Q(x)

只要使 v 满足特定的条件,代入解出对应的 u,就可以求出 y 了(反之亦然)。
可以看到,如果使 v'-P(x)v=0,方程就变为 u'=\dfrac{Q(x)}{v},可以直接积分求出 u
至于 v'-P(x)v=0,这不就是之前已经解决了的 一阶齐次线性微分方程 吗?
由此得到了 一阶线性微分方程 的通解:

v=C_ve^{\int P(x)\mathrm{d}x} u=C_v^{-1}(\int Q(x)e^{-\int P(x)\mathrm{d}x}\mathrm{d}x+C_u) y=uv=e^{\int P(x)\mathrm{d}x}(\int Q(x)e^{-\int P(x)\mathrm{d}x}\mathrm{d}x+C_u)

拉格朗日发现,这个通解满足 y=C(x)e^{\int P(x)\mathrm{d}x} 的形式。
其实不难理解,e^{\int P(x)\mathrm{d}x} 来自原本的 v,求解 u 的过程就是求解 C(x)
因此之后求解的时候就略去拆开 y 的过程,直接先解对应的齐次方程,
然后将常数变为函数代入回去,这就是一阶线性微分方程的常数变易法。

本题微分方程的常数变易法

接下来,让我们考虑本题的微分方程,它满足以下形式:

y'=P(x)f'^{-1}(y)+Q(x)

之前的经验告诉我们考虑对应的齐次方程:

y'=P(x)f'^{-1}(y) f'(y)y'=P(x) f(y)=\int P(x)\mathrm{d}x+C y=\operatorname{arc}f(\int P(x)\mathrm{d}x+C)

其中 \operatorname{arc}ff 对应的反函数,即

f:A\rightarrow B,\operatorname{arc}f:B\rightarrow A \forall x\in A,\operatorname{arc}f(f(x))=x \forall x\in B,f(\operatorname{arc}f(x))=x

推广到非齐次,我们猜想,本题微分方程通解的形式为:

y=\operatorname{arc}f(\int P(x)\mathrm{d}x+C(x))

接下来证明为什么这么做是正确的。
同样将 y 拆开,考虑到之前 u,v 与通解两项的对应,可认为

y=\operatorname{arc}f(v+u)

\operatorname{arc}f(x)=e^x 时,f'^{-1}(x)=x

$\operatorname{arc}f$ 值域 $=f$ 定义域 $\supseteq f'^{-1}$ 定义域, 因此仍然可以使 $f,v$ 满足特定的条件,代入解出对应的 $u$ 来求解 $y$。 代入 $y=\operatorname{arc}f(v+u)$,得 $$\operatorname{arc}f'(v+u)(v'+u')=P(x)f'^{-1}(\operatorname{arc}f(v+u))+Q(x)$$ 对 $f(\operatorname{arc}f(x))=x$ 求导,得 $$f'(\operatorname{arc}f(x))\operatorname{arc}f'(x)=1$$ $$\operatorname{arc}f'(x)=f'^{-1}(\operatorname{arc}f(x))$$ 因此原方程可化为 $$\operatorname{arc}f'(v+u)(v'+u')=P(x)\operatorname{arc}f'(v+u)+Q(x)$$ $$\operatorname{arc}f'(v+u)(v'+u'-P(x))=Q(x)$$ 若 $v'-P(x)=0$,解得 $v=\displaystyle\int P(x)\mathrm{d}x+C_v$ 。 因此之前通解的形式(常数变易法)是正确的。 ------------------------------ ## 本题微分方程的求解 回到本题的微分方程 $$y'=P(x)e^{y-1}+Q(x)$$ 此时 $f'^{-1}(x)=e^{x-1}$,设 $f(x)=-e^{1-x}$,则 $\operatorname{arc}f(x)=1-\ln(-x)$。 代入通解 $y=\operatorname{arc}f(\displaystyle\int P(x)\mathrm{d}x+C(x))$ 得 $$\operatorname{arc}f'(\int P(x)\mathrm{d}x+C(x))C'(x)=Q(x)$$ $$\frac{C'(x)}{\displaystyle-(\int P(x)\mathrm{d}x+C(x))}=Q(x)$$ $$C'(x)=-Q(x)C(x)-Q(x)\int P(x)\mathrm{d}x$$ 由此转化为一阶线性微分方程,解得 $$C(x)=e^{-\int Q(x)\mathrm{d}x}(\int(-Q(x)\int P(x)\mathrm{d}x)e^{\int Q(x)\mathrm{d}x}\mathrm{d}x+C_u)$$ $$y=\operatorname{arc}f(\int P(x)\mathrm{d}x+C(x))$$ $$=1-\ln(-\int P(x)\mathrm{d}x-C(x))$$ ------------------------------- 设 $A(x)=\displaystyle\int P(x)\mathrm{d}x,B(x)=\displaystyle e^{\int Q(x)\mathrm{d}x}$,则 $$C(x)=B^{-1}(x)(\int -Q(x)A(x)B(x)\mathrm{d}x+C_u)$$ $$y=1-\ln(-A(x)-C(x))$$ $$=1-\ln(-A(x)+B^{-1}(x)(\int Q(x)A(x)B(x)\mathrm{d}x-C_u))$$ $$=1+\ln B(x)-\ln(-A(x)B(x)+\int Q(x)A(x)B(x)\mathrm{d}x-C_u)$$ 由 $y(0)=1$ 得 $$\ln B(0)-\ln(-A(0)B(0)+\displaystyle\int^0 Q(x)A(x)B(x)\mathrm{d}x-C_u)=0$$ $$B(0)=-A(0)B(0)-C_u$$ $$-C_u=A(0)B(0)+B(0)=B(0)=1$$ $$y=1+\int Q(x)\mathrm{d}x-\ln(-A(x)B(x)+\int Q(x)A(x)B(x)\mathrm{d}x+1)$$ 已知 $B'(x)=Q(x)B(x),(A(x)B(x))'=A'(x)B(x)+A(x)B'(x)

于是得 Q(x)A(x)B(x)=A(x)B'(x)=(A(x)B(x))'-A'(x)B(x)

-A(x)B(x)+\int Q(x)A(x)B(x)\mathrm{d}x =-\int A'(x)B(x)\mathrm{d}x=-\int P(x)e^{\int Q(x)\mathrm{d}x}\mathrm{d}x y=1+\int Q(x)\mathrm{d}x-\ln(1-\int P(x)e^{\int Q(x)\mathrm{d}x}\mathrm{d}x)

由此得解,时间复杂度 \Theta(n\log n)

Code

/*
this code is made by warzone
2021.5.22 20:00
*/
#include<stdio.h>
#include<string.h>
typedef unsigned char byte;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned int word;
struct READ{//快读
    char c;
    inline READ(){c=getchar();}
    template<typename type>
    inline READ& operator>>(register type& num){
        while('0'>c||c>'9') c=getchar();
        for(num=0;'0'<=c&&c<='9';c=getchar())
            num=num*10+(c-'0');
        return *this;
    }
}cin;
class WRITE{//快写
    private:
        char out[1<<20],*top;
    public:
        inline WRITE(){top=out;}
        inline ~WRITE(){if(top!=out) fwrite(out,1,top-out,stdout);}
        inline WRITE& operator <<(char c){
            *(top++)=c;
            if(top==out+(1<<20))
                fwrite(top=out,1,1<<20,stdout);
            return *this;
        }
        inline void outnum(word num){
            if(num) outnum(num/10),*this<<(char)(num%10+'0');
        }
        template<typename type>
        inline WRITE& operator <<(type num){
            if(num) return outnum(num),*this;
            return *this<<'0';
        }
}cout;
#define mx 18
#define mx_ 17
word root[1<<mx],inv[1<<mx],realid[1<<mx];
ull size,ni2;
const word mod=998244353;
inline ull pow(register ull a,register word b){
    register ull ans=1;
    for(;b;b>>=1){
        if(b&1) (ans*=a)%=mod;
        (a*=a)%=mod;
    }
    return ans;
}
//预处理单位根,翻转的 id
#define loading()           \
    register ull num1=pow(3,(mod-1)>>mx);   \
    register ull num2=pow(num1,mod-2);  \
    register word head,i,floor; \
    root[1<<mx_]=inv[1<<mx_]=1; \
    ni2=pow(2,mod-2);       \
    for(i=1;head=i,i<(1<<mx);++i)   \
        for(floor=0;floor<mx;++floor,head>>=1)  \
            realid[i]=realid[i]<<1|(head&1);    \
    for(i=1;i<(1<<mx_);++i){    \
        root[1<<mx_|i]=num1*root[1<<mx_|(i-1)]%mod; \
        inv[1<<mx_|i]=num2*inv[1<<mx_|(i-1)]%mod;   \
    }   \
    for(i=(1<<mx_)-1;i;--i) \
        root[i]=root[i<<1],inv[i]=inv[i<<1];
#define load()  \
    register ull num1,num2;\
    register word head,i,floor;
#define nttfor(size)    \
    for(floor=1;floor<1u<<(size);floor<<=1) \
        for(head=0;head<1u<<(size);head+=floor<<1)  \
            for(i=0;i<floor;++i)
//floor 变换区间大小
//head 变换区间头指针 
//i 变换位置 
#define ntt(num,root)(  \
    num1=(num)[head|i], \
    num2=(num)[head|i|floor],   \
    (num)[head|i]=(num1+((num2*=root[i|floor])%=mod))%mod,  \
    (num)[head|i|floor]=(num1+mod-num2)%mod)
#define id(size,i) (realid[i]>>(mx-(size)))
#define modx(num,size) memset(num+(1<<(size)),0,4<<(size))
#define set0(num,size) memset(num,0,4<<(size))
#define FOR(size) for(i=0;i<1u<<(size);i++)
#define newton(size)    \
    ull ni=ni2,size_=1; \
    while(size_++,ni=ni*ni2%mod,size_-2<(size))
word in[1<<mx],eax[1<<mx],ebx[1<<mx],ecx[1<<mx],edx[1<<mx];
word out[1<<mx];
inline void _1(word size){//求 eax 的逆元,放入 ebx
    ebx[0]=pow(eax[0],mod-2);
    load()
    newton(size){
        FOR(size_-1){
            head=id(size_,i);
            ecx[head]=eax[i]? mod-eax[i]:0;
            edx[head]=ebx[i];
            head=id(size_,i+(1<<(size_-1)));
            ecx[head]=edx[head]=0;
        }
        nttfor(size_) ntt(ecx,root),ntt(edx,root);
        FOR(size_) ebx[id(size_,i)]=(ull)(ecx[i])*edx[i]%mod;
        nttfor(size_) ntt(ebx,inv);
        modx(ebx,size_-1);
        FOR(size_) ecx[id(size_,i)]=ni*ebx[i]%mod;
        ecx[0]=(ecx[0]+2)%mod;
        nttfor(size_) ntt(ecx,root);
        FOR(size_) ebx[id(size_,i)]=(ull)(ecx[i])*edx[i]%mod;
        nttfor(size_) ntt(ebx,inv);
        modx(ebx,size_-1);
        FOR(size_-1) ebx[i]=ni*ebx[i]%mod;
    }
}
inline void ln(word size){//求 eax 的 ln,放入 ebx
    _1(size);
    load()
    FOR(size){
        head=id(size+1,i);
        ecx[head]=ebx[i];
        edx[head]=(ll)(eax[i+1])*(i+1)%mod;
        head=id(size+1,i+(1<<size));
        ecx[head]=edx[head]=0;
    }
    nttfor(size+1) ntt(ecx,root),ntt(edx,root);
    FOR(size+1) ebx[id(size+1,i)]=(ull)(ecx[i])*edx[i]%mod;
    nttfor(size+1) ntt(ebx,inv);
    modx(ebx,size);
    for(register word i=(1u<<size)-1,ni=pow(1u<<(size+1),mod-2);i>0;i--)
        ebx[i]=pow(i,mod-2)*ebx[i-1]%mod*ni%mod;
    ebx[0]=0;
}
inline void exp(word size){// 求 in 的逆元,放入 eax
    eax[0]=1;
    load();
    newton(size){
        ln(size_-1);
        FOR(size_-1){
            head=id(size_,i);
            ecx[head]=eax[i];
            edx[head]=(mod-ebx[i]+in[i])%mod;
            head=id(size_,i+(1<<(size_-1)));
            ecx[head]=edx[head]=0;
        }
        edx[0]=(1ull+edx[0])%mod;
        nttfor(size_) ntt(ecx,root),ntt(edx,root);
        FOR(size_) eax[id(size_,i)]=(ull)(ecx[i])*edx[i]%mod;
        nttfor(size_) ntt(eax,inv);
        modx(eax,size_-1);
        FOR(size_-1) eax[i]=ni*eax[i]%mod;
    }
}
int main(){
    loading();
    word n,size=0;
    cin>>n;
    for(;1u<<size<=n+1;size++);
    for(i=0;i<=n;++i)
        cin>>out[id(size+1,i)];
    for(i=1;i<=n+1;++i)
        cin>>num1,in[i]=pow(i,mod-2)*num1%mod;
    exp(size);
    FOR(size){
        ecx[id(size+1,i)]=eax[i]? mod-eax[i]:0;
        ecx[id(size+1,i+(1u<<size))]=0;
    }
    nttfor(size+1) ntt(out,root),ntt(ecx,root);
    FOR(size+1) ebx[id(size+1,i)]=(ull)(out[i])*ecx[i]%mod;
    nttfor(size+1) ntt(ebx,inv);
    eax[0]=1;
    num1=pow(1u<<(size+1),mod-2);
    for(i=1;i<1u<<(size);++i)
        eax[i]=pow(i,mod-2)*num1%mod*ebx[i-1]%mod;
    ln(size);
    ++in[0];
    for(register word i=0;i<=n;i++)
        cout<<((ull)(in[i])+mod-ebx[i])%mod<<' ';
    return 0;
}