• [CTSC2018]青蕈领主


    [CTSC2018]青蕈领主 

    题解

    首先,连续段要知道结论:

    连续段要么不交,要么包含

    所以是一棵树!每个位置的father是后面第一个包含它的

    树形DP!

    设dp[x],x为根的子树,(设管辖的区间长度为len,也即L[x]),用1~len的数填充,满足L的方案数

    也就是,每个son内部合法,

    给每个son分配标号区间,使得相邻儿子不会再接在一起

    不会再接在一起?

     所以可以把每个儿子看成单独一个点,就划归成了:1,1,1,1,...len的方案数!

    设f[i]表示,长度为i+1的1,1,1,1....i+1的序列的合法方案数。

    $dp[x]=(Pi dp[son]) imes f[L[x]]$

    归纳一下,可得$ans=Pi f[|son(x)|]$,$|son(x)|$表示x的儿子个数

    求f[n]?

    考虑变成排列的逆!

    (也就是把映射矩阵的横纵坐标意义交换)

    这样,n+1成为了天然的分割点。

    f[n-1]中,填入1,

    要么之前合法。

    要么1分开了一些东西

    |son(x)|可以直接单调栈

    注意,Poly每次clear需要重新resize

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    namespace Modulo{
    const int mod=998244353;
    int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
    void inc(int &x,int y){x=ad(x,y);}
    int sub(int x,int y){return ad(x,mod-y);}
    int mul(int x,int y){return (ll)x*y%mod;}
    void inc2(int &x,int y){x=mul(x,y);}
    int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
    template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);}
    template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);}
    }  
    using namespace Modulo;
    namespace Miracle{
    const int N=50000+5;
    const int G=3;
    const int GI=332748118;
    int n,T;
    int L[N];
    struct Poly{
        vector<int>f;
        Poly(){f.clear();}
        il int &operator[](const int &x){assert(x<f.size());return f[x];}
        il void resize(int n){f.resize(n);}
        il int size(){return f.size();}
        il void clear(){f.clear();}
        il void out(){for(reg i=0;i<(int)f.size();++i) ot(f[i]);putchar('
    ');}
    }f;
    int rev[8*N];
    int init(int n){
        int m=0;
        for(m=1;m<n;m<<=1);
        for(reg i=0;i<m;++i){
            rev[i]=(rev[i>>1]>>1)|((i&1)?m>>1:0);
        }
        return m;
    }
    void NTT(Poly &f,int c){
        int n=f.size();
        for(reg i=0;i<n;++i){
            if(i<rev[i]) swap(f[i],f[rev[i]]);
        }
        for(reg p=2;p<=n;p<<=1){
            int gen;
            if(c==1) gen=qm(G,(mod-1)/p);
            else gen=qm(GI,(mod-1)/p);
            for(reg l=0;l<n;l+=p){
                int buf=1;
                for(reg i=l;i<l+p/2;++i){
                    int tmp=mul(f[i+p/2],buf);
                    f[i+p/2]=ad(f[i],mod-tmp);
                    f[i]=ad(f[i],tmp);
                    buf=mul(buf,gen);
                }
            }
        }
        if(c==-1){
            int iv=qm(n);
            for(reg i=0;i<n;++i){
                f[i]=mul(f[i],iv);
            }
        }
    }
    il Poly operator *(Poly F,Poly G){
        int n=init(F.size()+G.size()-1);
        F.resize(n);G.resize(n);
        NTT(F,1);NTT(G,1);
        for(reg i=0;i<n;++i) F[i]=mul(F[i],G[i]);
        NTT(F,-1);
        return F;
    }
    void divi(int l,int r){
        
        if(l==0&&r==1){
            f[0]=1;f[1]=2;return;
        }
        if(l==r){
            f[l]=ad(f[l],mod-mul(f[1],f[l-1],l-2));
            f[l]=ad(f[l],mul(l-1,f[l-1]));
            return;
        }
        int mid=(l+r)>>1;
        divi(l,mid);
        // cout<<" divi ---------------------------"<<l<<" "<<r<<endl;
        Poly F,G,K;
        if(l==0){
            // goto s;
            // cout<<"sol1---- "<<endl;
            F.resize(mid+1);
            G.resize(mid+1);
            for(reg i=1;i<=mid;++i){
                F[i]=f[i];
                G[i]=mul(f[i],i-1);
            }
            // F.out();
            // G.out();
            // cout<<"hahahaha "<<endl;
            F=F*G;
            // F.out();
            
            for(reg i=mid+1;i<=r;++i){
                f[i]=ad(f[i],F[i]);
            }
            // cout<<" over "<<endl;
        }else{
            
            // cout<<"sol2**** "<<endl;
            F.resize(mid-l+1);
            G.resize(r-l+1);
            for(reg i=0;i<=mid-l;++i){
                F[i]=f[i+l];
            }
            for(reg i=1;i<=r-l;++i){
                G[i]=mul(f[i],i-1);
            }
            // F.out();
            // G.out();
            // cout<<" mul "<<endl;
            K=F*G;
            // cout<<" K "<<endl;
            // K.out();
    
            for(reg i=mid+1;i<=r;++i){
                f[i]=ad(f[i],K[i-l]);
            }
            
            F.clear();G.clear();
            F.resize(mid-l+1);G.resize(r-l+1);
    
            // cout<<F.size()<<" len "<<mid-l+1<<endl;
            for(reg i=0;i<=mid-l;++i){
                F[i]=mul(f[i+l],i+l-1);
            }
            // cout<<" OK ? "<<endl;
            for(reg i=1;i<=r-l;++i){
                G[i]=f[i];
            }
            
            K=F*G;
            for(reg i=mid+1;i<=r;++i){
                f[i]=ad(f[i],K[i-l]);
            }
        }
        // s:;
        // cout<<" end "<<f[3]<<endl;
        divi(mid+1,r);
    }
    int sta[N],top;
    int main(){
        rd(T);rd(n);
        int m=init(n+1);
        f.resize(m);
        
        divi(0,m-1);
        // f.out();
    
        while(T--){
            for(reg i=1;i<=n;++i) rd(L[i]);
            top=0;
            if(L[n]!=n) {
                puts("0");continue;
            }
            int ans=1;
            bool fl=true;
            for(reg i=1;i<=n;++i){
                int son=0;
                while(top&&sta[top]-L[sta[top]]+1>=i-L[i]+1) ++son,--top;
                // cout<<" ii "<<i<<" son "<<son<<endl;
                if(top){
                    if(sta[top]>=i-L[i]+1) fl=false;
                }
                sta[++top]=i;
                ans=mul(ans,f[son]);
            }
            if(!fl) ans=0;
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    树形结构!

    然后递归为子问题。

    递归为子问题,把。。。看成。。。。

    本质就是“缩点”找相似结构。或者归纳

  • 相关阅读:
    模糊查询(排除%等通配符并支持不连续关键字查询)
    ideal中运行manven常用操作
    ideal项目启动及问题
    FastJSON 转换List<T> ,Map<T,T>泛型失败 处理方法
    MySQL的SELECT ...for update
    CouchDB客户端开发—Java版
    Spring Data JPA 实例查询
    第一章 计算机网络概述
    第二章 物理层(二)
    Java常考面试题(一)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/11019351.html
Copyright © 2020-2023  润新知