「CF623E-Transforming Sequence」题解

E. Transforming Sequence

sol

考虑设计 DP,令 \(f_{i,j}\) 表示长为 \(i\) 的合法序列或和为 \(2^j-1\) 的方案数。

先不说转移,这个状态一眼看上去难以转化为答案,但实际上并不困难。答案可以表示为:

\[\sum_{j=1}^k \binom{k}{j}f_{n,j} \]

考虑在 \(k\) 位中选出 \(j\) 位,其余位显然可以不考虑,此时这种情况的方案等价于凑出 \(2^j-1\) 的方案。

然后考虑转移,我们先给出递推式:

\[f_{n,k}=\sum_{i=1}^{k-1}f_{n-1,i}\binom{k}{i}2^i \]

接下来解释这个式子,想凑出 \(k\)\(1\),可以枚举上一步凑出了多少 \(1\)\(\binom{k}{i}\) 即为上一步凑出的 \(1\) 在当前结果中的位置。但我们需要考虑数列中两个数存在一些位均为 \(1\) 的重合情况,不难发现对于这一步的新数而言,上一步已经凑出的 \(1\) 的位置,其可以任意为 \(1\)\(0\),共 \(2^i\) 种情况。由于严格单调递增,这里 \(i\) 的枚举上限应为 \(k-1\)。严格上来说下限应为 \(n-1\),但考虑不合法情况 \(f_{n-1,i}=0\),不会造成影响。

但这样一层层枚举显然会 T 爆,我们发现其实不用一位一位加入新点,而可以把一个序列视作两个序列的拼接,于是可得:

\[f_{x,y}=\sum_{n=0}^{x}\sum_{m=0}^{x}\sum_{i=0}^y\sum_{j=0}^y\left[n+m=x\land i+j=y\right]f_{n,i}f_{m,j}\binom{y}{i}2^{mi} \]

其余定义是类似的,我们只额外讲一下最后 \(2^{mi}\) 的含义。假令长 \(m\) 的序列为新拼接入的序列,那么对于其每个元素,\(i\) 个原先为 \(1\) 的位均可自由选择,于是就有了 \(2^{mi}\) 种情况。这里的上下界均宽松,因为不合法状态 \(f=0\) 所以没有影响。

到这里其实已经很简单了,上面很显然是一个卷积状物,下面详细讲解一下卷积部分。

展开可得:

\[\begin{align*} &\sum_{i=0}^y\sum_{j=0}^y\left[i+j=y\right]f_{n,i}f_{m,j}\binom{y}{i}2^{mi}\\ =&y!\sum_{i=0}^y\sum_{j=0}^y\left[i+j=y\right]\frac{f_{n,i}2^{mi}}{i!}\cdot\frac{f_{m,j}}{j!} \end{align*} \]

为了方便,我们转为维护 \(f'_{i,j}=\frac{f_{i,j}}{j!}\),同时额外维护 \(\frac{f_{n,i}2^{mi}}{i!}\),显然可以在每次转移前得到 \(m\) 的值。

然后就很简单了,倍增即可。卷积部分需要使用 MTT。

code

namespace MTT{
    int P=1e9+7;
    struct clx{
        flt x,y;
        clx(flt a=0,flt b=0){x=a,y=b;}
        inline clx operator+=(const clx &b){return x+=b.x,y+=b.y,*this;}
        friend inline clx operator+(clx a,clx b){return a+=b;}
        inline clx operator-=(const clx &b){return x-=b.x,y-=b.y,*this;}
        friend inline clx operator-(clx a,clx b){return a-=b;}
        inline clx operator*=(const clx &b){return *this=clx(x*b.x-y*b.y,x*b.y+y*b.x);}
        friend inline clx operator*(clx a,clx b){return a*=b;}
        inline clx operator!(){return clx(x,-y);}
    };
    typedef vec<ll> poly;
    typedef vec<clx> Poly;
    const flt Pi=acos(-1);
    vec<int> Rt;
    inline void fft(int lim,Poly &a,int type){
        repl(i,0,lim)if(i<Rt[i])swap(a[i],a[Rt[i]]);
        for(int mid=1;mid<lim;mid<<=1){
            clx w1(cos(Pi/mid),type*sin(Pi/mid));
            for(int j=0;j<lim;j+=(mid<<1)){
                clx w(1,0);
                repl(k,0,mid){
                    clx x=a[j+k],y=w*a[j+mid+k];
                    a[j+k]=x+y;
                    a[j+mid+k]=x-y;
                    w=w*w1;
                }
            }
        }
    }
    inline void operator*=(poly &x,poly y){
        int n=x.size(),m=y.size(),M=ceil(sqrt(P));
        int lim=1,l=0,len=n+m-1;
        while(lim<len)lim<<=1,l++;
        Rt.resize(lim);
        repl(i,0,lim)Rt[i]=(Rt[i>>1]>>1)|((i&1)<<(l-1));
        Poly p(lim),q(lim),s(lim),t(lim);
        x.resize(lim),y.resize(lim);
        repl(i,0,lim)p[i]=clx(x[i]/M,x[i]%M),q[i]=clx(y[i]/M,y[i]%M);
        fft(lim,p,1);fft(lim,q,1);
        repl(i,0,lim){
            clx ka=(p[i]+!p[i?lim-i:i])*clx(0.5,0);
            clx ba=(p[i]-!p[i?lim-i:i])*clx(0,-0.5);
            clx kb=(q[i]+!q[i?lim-i:i])*clx(0.5,0);
            clx bb=(q[i]-!q[i?lim-i:i])*clx(0,-0.5);
            s[i]=ka*kb+ka*bb*clx(0,1);
            t[i]=ba*kb+ba*bb*clx(0,1);
        }
        fft(lim,s,-1);fft(lim,t,-1);
        repl(i,0,lim){
            ll a=(ll)(s[i].x/lim+0.5)%P;
            ll b=(ll)(s[i].y/lim+0.5)%P;
            ll c=(ll)(t[i].x/lim+0.5)%P;
            ll d=(ll)(t[i].y/lim+0.5)%P;
            x[i]=a*M*M%P+(b+c)*M%P+d,x[i]%=P;
        }
        x.resize(len);
        for(auto &i:x)i=(i+P)%P;
    }
    inline void operator+=(poly &a,poly b){
        if(a.size()<b.size())a.resize(b.size());
        repl(i,0,b.size())a[i]=a[i]+b[i],a[i]%=P;
    }
    inline void operator-=(poly &a,poly b){
        if(a.size()<b.size())a.resize(b.size());
        repl(i,0,b.size())a[i]=a[i]-b[i]+P,a[i]%=P;
    }
    poly operator*(poly a,poly b){return a*=b,a;}
    poly operator+(poly a,poly b){return a+=b,a;}
    poly operator-(poly a,poly b){return a-=b,a;}
}using namespace MTT;

const int T=65,N=3e4+5;

ll n;int k;
poly f[T],g[T],ans;
mint jc[N],iv[N];

inline void Main(){
    read(n,k);
    f[0].resize(k+1);g[0].resize(k+1);
    rep(j,1,k)f[0][j]=iv[j].x,g[0][j]=(f[0][j]*((mint)2^j)).x;
    int tt=__lg(n);
    rep(t,1,tt){
        f[t]=g[t-1]*f[t-1];f[t].resize(k+1);
        g[t].resize(k+1);rep(j,1,k)g[t][j]=(f[t][j]*((mint)2^(1ll<<t)^j)).x;
    }
    ans.resize(k+1);
    ans[0]=1;
    rep(t,0,tt)if(n&1ll<<t){
        rep(j,1,k)ans[j]*=((mint)2^(1ll<<t)^j).x,ans[j]%=P;
        ans*=f[t];ans.resize(k+1);
    }
    mint res=0;
    rep(i,1,k)res+=ans[i]*jc[i]*jc[k]*iv[i]*iv[k-i];
    put(res);
}
posted @ 2025-06-26 17:19  LastKismet  阅读(9)  评论(0)    收藏  举报