连续段 - dp - 多项式理论 - 牛顿迭代

题目大意:
对每个 n [ 1 , N ] n\in[1,N] 求有多少长为 n n 的本质不同的排列,其中两个排列 p 1 , p 2 p_1,p_2 本质相同,当且仅当 S ( p 1 ) = S ( p 2 ) S(p_1)=S(p_2) ,其中:
S ( p ) = { [ l , r ] 1 l r p , ( min i = l r p i ) ( max i = l r p i ) = r l } S(p)=\{[l,r]|1\le l\le r\le|p|,(\min_{i=l}^rp_i)-(\max_{i=l}^rp_i)=r-l\}
n 1 0 5 n\le10^5 ,对 P = k × 2 18 + 1 P=k\times2^{18}+1 取模, P P 为质数。
题解:
考虑给你一个排列 p p
称一个区间是强连续的当且仅当区间中值与下标的和全相等,或者差全相等。
那么我们将所有极长的强连续区间缩起来,这样就变成一个子问题。
但是有可能一个区间不存在长度大于等于2的强连续区间,但是发现一个排列不存在长度大于等于2的强连续区间当且仅当其长度大于等于4,并且只存在一种本质不同的这样的排列。
因此将上述过程描述成一颗树,一个点要么为叶子,要么是强连续区间,要么是直接全缩起来的。第二种情况要至少两个儿子,第三种情况要至少四个儿子。
因此设 F ( x ) F(x) 为确定叶子数量答案的生成函数,那么显然:
F ( x ) = x + F 2 ( x ) 1 x + F 4 ( x ) 1 x F(x)=x+\frac{F^2(x)}{1-x}+\frac{F^4(x)}{1-x}
牛顿迭代上式即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace OUTPUT_SPACE{
    char ss[2000000],tt[30];int ssl,ttl;
    inline int print(int x)
    {
        if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
        for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
    }
    inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int p,yg,pri[100];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
inline int get_yg()
{
    int c=0,x=p-1;
    rep(i,2,x/i) if(x%i==0) for(pri[++c]=i,x/=i;x%i==0;x/=i);
    for(yg=2;;yg++)
    {
        int ok=1;
        rep(i,1,c) if(fast_pow(yg,(p-1)/pri[i])==1) { ok=0;break; }
        if(ok) return 0;
    }
    return 0;
}
namespace NTT_space{
    const int N=1000010;int A[N],B[N],r[N];
    inline int show(int *a,int n) { rep(i,0,n-1) cerr<<a[i]sp;cerr ln;return 0; }
    inline void clr(int *a,int n) { memset(a,0,sizeof(int)*n); }
    inline void cpy(int *a,int *b,int n) { memcpy(a,b,sizeof(int)*n); }
    inline int NTT(int *a,int n,int s)
    {
        int t=1,L=0;while(t<n) t<<=1,L++;
        rep(i,1,n-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
        rep(i,1,n-1) if(i<r[i]) swap(a[i],a[r[i]]);
        for(int i=2;i<=n;i<<=1)
        {
            int wn=fast_pow(yg,s>0?(p-1)/i:p-1-(p-1)/i);
            for(int j=0,t=i>>1,x,y;j<n;j+=i)
                for(int k=0,w=1;k<t;k++,w=(lint)w*wn%p)
                    x=a[j+k],y=(lint)w*a[j+k+t]%p,a[j+k]=x+y,a[j+k+t]=x-y,
                    (a[j+k]>=p?a[j+k]-=p:0),(a[j+k+t]<0?a[j+k+t]+=p:0);
        }
        if(s<0) for(int i=0,ninv=fast_pow(n,p-2);i<n;i++) a[i]=(lint)a[i]*ninv%p;
        return 0;
    }
    inline int tms(int *a,int m1,int *b,int m2,int *c,int m3=-1)
    {
        int n=1;while(n<m1+m2-1) n<<=1;
        clr(A,n),cpy(A,a,m1),NTT(A,n,1);
        clr(B,n),cpy(B,b,m2),NTT(B,n,1);
        rep(i,0,n-1) A[i]=(lint)A[i]*B[i]%p;
        return NTT(A,n,-1),cpy(c,A,m3<0?m1+m2-1:m3),0;
    }
    namespace POLYINV_space{
        int b[N],h[N];
        inline int polyinv(int *a,int m,int *res)
        {
            int n=1;while(n<m) n<<=1;
            clr(b,n),b[0]=fast_pow(a[0],p-2);
            for(int i=2;i<=m;i<<=1)
            {
                cpy(h,b,i);rep(j,0,(i>>1)-1) h[j]+=h[j],(h[j]>=p?h[j]-=p:0);
                tms(b,i>>1,b,i>>1,b,i),tms(b,i,a,i,b,i);
                rep(j,0,i-1) b[j]=h[j]-b[j],(b[j]<0?b[j]+=p:0);
            }
            return cpy(res,b,m),0;
        }
    }using POLYINV_space::polyinv;
    int fs[N];
    namespace SOLVE_space{
        int f[N],a[N],b[N];
        inline int solve(int m,int *ans)
        {
            int n=1;while(n<=m) n<<=1;
            clr(f,n),f[0]=0;
            for(int i=2;i<=n;i<<=1)
            {
                int t=i<<1,w=1,wn=fast_pow(yg,(p-1)/t),f1,f2,f3,f4;
                cpy(fs,f,i>>1),NTT(f,t,1);
                rep(j,0,t-1)
                    f1=f[j],f2=(lint)f1*f1%p,f3=(lint)f2*f1%p,f4=(lint)f2*f2%p,
                    a[j]=(f4+2ll*f2-(w+1ll)*f1+w)%p,(a[j]<0?a[j]+=p:0),
                    b[j]=(4ll*f3+4ll*f1-w-1)%p,(b[j]<0?b[j]+=p:0),w=(lint)w*wn%p;
                NTT(b,t,-1),polyinv(b,i,b),NTT(a,t,-1),tms(a,i,b,i,a,i);
                cpy(f,fs,i>>1),clr(f+(i>>1),t-(i>>1));
                rep(j,0,i-1) f[j]-=a[j],(f[j]<0?f[j]+=p:0);
            }
            return cpy(ans,f,m+1),0;
        }
    }using SOLVE_space::solve;
}
const int N=100010;
int ans[N];
int main()
{
    int n=inn();p=inn(),get_yg();
    NTT_space::solve(n,ans);
    rep(i,1,n) print(ans[i]);
    return Flush(),0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/85385019