zoukankan      html  css  js  c++  java
  • LOJ575 「LibreOJ NOI Round #2」不等关系

    Link
    若忽略掉>的限制,那么问题等价于将(1,cdots,n)填入若干个长度为(a_1,cdots,a_m)的递增序列,方案数为(frac{n!}{prod a_i!})
    >可以用容斥来计算,考虑把这个容斥的过程写成dp,设(i!f_i)(pre(i))的合法排列数,那么我们有

    [f_0=1,f_i=sumlimits_{j=0}^{i-1}[s_j e<](-1)^{cnt_{i-1}-cnt_j}f_jfrac1{(i-j)!} ]

    其中(cnt_i)(pre(i))>的出现次数。分治FFT即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using i64=long long;
    const int N=1<<18,P=998244353;
    char str[N];int len,rev[N],cnt[N];i64 fac,w[N],ifac[N],f[N];
    void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
    void dec(i64&a,i64 b){a-=b,a+=a>>63&P;}
    i64 pow(i64 a,int b){i64 r=1;for(;b;b>>=1,a=a*a%P)if(b&1)r=r*a%P;return r;}
    int getlen(int n){return 1<<(32-__builtin_clz(n));}
    void init(int n)
    {
        int lim=1<<(len=32-__builtin_clz(n)),pos=lim/2;i64 g=pow(3,(P-1)/lim);
        for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? pos:0);
        w[pos]=1;for(int i=pos+1;i<lim;++i) w[i]=g*w[i-1]%P;
        for(int i=pos-1;i;--i) w[i]=w[i<<1];
        fac=1;for(int i=1;i<=n;++i) fac=i*fac%P;
        ifac[n]=pow(fac,P-2);for(int i=n;i;--i) ifac[i-1]=i*ifac[i]%P;
    }
    void NTT(i64*a,int lim,int f)
    {
        if(!~f) std::reverse(a+1,a+lim);
        for(int i=0,x=len-__builtin_ctz(lim);i<lim;++i) if(i<rev[i]>>x) std::swap(a[i],a[rev[i]>>x]);
        for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=w[i+k]*a[i+j+k]%P,dec(a[i+j+k]=a[j+k],x),inc(a[j+k],x);
        if(!~f) for(int i=0,x=P-(P-1)/lim;i<lim;++i) a[i]=x*a[i]%P;
    }
    void solve(int l,int r)
    {
        static i64 a[N],b[N];
        if(l==r) return f[l]=!l? 1:str[l]=='<'? 0:cnt[l-1]&1? P-f[l]:f[l],void();
        int mid=(l+r)/2,lim=getlen(r-l+1);solve(l,mid);
        memset(a,0,8*lim),memset(b,0,8*lim),memcpy(b+1,ifac+1,8*(r-l));
        for(int i=l;i<=mid;++i) a[i-l]=cnt[i]&1? P-f[i]:f[i];
        NTT(a,lim,1),NTT(b,lim,1);
        for(int i=0;i<lim;++i) a[i]=a[i]*b[i]%P;
        NTT(a,lim,-1);
        for(int i=mid+1;i<=r;++i) inc(f[i],a[i-l]);
        solve(mid+1,r);
    }
    int main()
    {
        scanf("%s",str+1);int n=strlen(str+1)+1;init(n);
        for(int i=1;i<=n;++i) cnt[i]=cnt[i-1]+(str[i]=='>');
        solve(0,n),printf("%lld",fac*f[n]%P);
    }
    
  • 相关阅读:
    codevs 2021 中庸之道
    bzoj 1227: [SDOI2009]虔诚的墓主人
    cogs 2620. [HEOI2012]朋友圈
    bzoj 3123: [Sdoi2013]森林(45分暴力)
    cogs 1685 魔法森林
    bzoj 1061: [Noi2008]志愿者招募
    poj 1743 Musical Theme
    bzoj 1001: [BeiJing2006]狼抓兔子
    bzoj 4006: [JLOI2015]管道连接
    hdu 5693 D Game
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13041675.html
Copyright © 2011-2022 走看看