zoukankan      html  css  js  c++  java
  • [题解] LuoguP5339 [TJOI2019]唱、跳、rap和篮球

    0202年写这个是不是晚了啊...算了还是加一句鸡你太美吧...


    https://www.luogu.com.cn/problem/P5339

    这里是二项式反演的套路做法...

    (F[k])表示恰好有(k)组鸡你太美的方案数

    (G[k])表示我钦定(k)组鸡你太美,然后其他位置随便放的方案数

    那么答案就是(F[0])

    考虑钦定(k)组鸡你太美的位置的方案数,我们把一组鸡你太美缩成(1)个点,那么就有(n-3k)个点,在这些点中随便选(k)个点展开来作为一组鸡你太美就唯一对应了一个安排(k)组鸡你太美的方案,所以钦定位置的方案数是(inom{n-3k}{k})

    然后剩余的人挑(n-4k)个人出来做全排列(下面令(c[i])表示第(i)类人的人数),这就是就是一个生成函数的套路东西,考虑第(i)类人选了(cc[i])(cc[i]le c[i]-k))个,那么这个选剩下的人出来排列的方案数就是

    [sumlimits_{cc[1]+cc[2]+cc[3]+cc[4]=n-4k}frac{(n-4k)!}{cc[1]!cc[2]!cc[3]!cc[4]!} ]

    ((n-4k)!)放到外面,然后构造(4)类人的生成函数

    (A(x)=sumlimits_{i=0}^{c[1]-k}frac{1}{i!}x^i)(B,C,D)类似(A),分别表示第(2,3,4)类人的生成函数

    所以排列的方案数就是((n-4k)![x^{n-4k}]A(x)B(x)C(x)D(x)),注意到良心模数(998244353)(NTT)就好了。

    所以(G[k]=inom{n-3k}{k}(n-4k)![x^{n-4k}]A(x)B(x)C(x)D(x))

    但我们要求的是(F)...

    考虑(F)(G[k])的关系,枚举最后有(i)组鸡你太美,然后由于是先钦定(k)组,所以(F[i])还要乘上(inom{i}{k}),有

    [G[k]=sumlimits_{ige k} inom{i}{k}F[i] ]

    二项式反演得到

    [F[k]=sumlimits_{ige k} (-1)^{i-k}inom{i}{k} G[i] ]

    答案就是

    [F[0]=sumlimits_{ige 0} (-1)^{i-k}inom{i}{k}G[i] ]

    我们可以在(O(nlog n))的时间内算出(G[i]),最后复杂度(O(n^2 log n))

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;++i)
    #define per(i,a,n) for (int i=n-1;i>=a;--i)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    #define SZ(x) ((int)(x).size())
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    
    const int N=1e5+10,P=998244353,gn=3,ign=(P+1)/gn;
    inline int add(int x,int y) {return (x+=y)>=P?x-P:x;}
    inline int sub(int x,int y) {return (x-=y)<0?x+P:x;}
    inline int fpow(int x,int y) {
        int ret=1; for(;y;y>>=1,x=1ll*x*x%P)
            if(y&1) ret=1ll*ret*x%P;
        return ret;
    }
    
    namespace Poly {
        int rev[N];
    
        inline void init(int n) {rep(i,0,n) rev[i]=rev[i>>1]>>1|((i&1)?n>>1:0);}
    
        void ntt(int *f,int n,int flg) {
            rep(i,0,n) if(rev[i]<i) swap(f[i],f[rev[i]]);
            for(int len=2,k=1;len<=n;len<<=1,k<<=1) {
                int wn=fpow(flg==1?gn:ign,(P-1)/len);
                for(int i=0;i<n;i+=len)
                    for(int j=i,w=1;j<i+k;j++,w=1ll*w*wn%P) {
                        int tmp=1ll*f[j+k]*w%P;
                        f[j+k]=sub(f[j],tmp),f[j]=add(f[j],tmp);
                    }
            }
            if(flg==-1) {
                int inv=fpow(n,P-2);
                rep(i,0,n) f[i]=1ll*f[i]*inv%P;
            }
        }
    }
    using Poly::ntt;
    
    int inv[N],fac[N],ifac[N];
    void init(int n) {
        fac[0]=fac[1]=ifac[0]=ifac[1]=inv[1]=1;
        rep(i,2,n+1) {
            inv[i]=1ll*inv[P%i]*(P-P/i)%P;
            fac[i]=1ll*fac[i-1]*i%P;
            ifac[i]=1ll*ifac[i-1]*inv[i]%P;
        }
    }
    inline int getC(int n,int r) {return n<r?0:1ll*fac[n]*ifac[n-r]%P*ifac[r]%P;}
    
    int F[4][N];
    inline int getP(int n,int c1,int c2,int c3,int c4) {
        rep(i,0,c1+1) F[0][i]=ifac[i];
        rep(i,0,c2+1) F[1][i]=ifac[i];
        rep(i,0,c3+1) F[2][i]=ifac[i];
        rep(i,0,c4+1) F[3][i]=ifac[i];
        int limit=1; while(limit<=c1+c2+c3+c4) limit<<=1; Poly::init(limit);
        ntt(F[0],limit,1),ntt(F[1],limit,1),ntt(F[2],limit,1),ntt(F[3],limit,1);
        rep(i,0,limit) F[0][i]=1ll*F[0][i]*F[1][i]%P*F[2][i]%P*F[3][i]%P;
        ntt(F[0],limit,-1); 
        int ans=1ll*fac[n]*F[0][n]%P;
        rep(i,0,limit) F[0][i]=F[1][i]=F[2][i]=F[3][i]=0;
        return ans;
    }
    
    int n,c[4];
    inline int getG(int k) {return 1ll*getC(n-3*k,k)*getP(n-4*k,c[0]-k,c[1]-k,c[2]-k,c[3]-k)%P;}
    
    int main() {
    #ifdef LOCAL
        freopen("a.in","r",stdin);
    #endif
        scanf("%d%d%d%d%d",&n,c,c+1,c+2,c+3);
        init(max(n,c[0]+c[1]+c[2]+c[3])); int ans=0,lim=min(n/4,min(c[0],min(c[1],min(c[2],c[3]))));
        rep(i,0,lim+1) ans=add(ans,1ll*((i&1)?P-1:1)*getG(i)%P);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Https协议详解
    python3爬虫之入门和正则表达式
    浅谈httpsssl数字证书
    Linux常见配置文件
    标准C++中的string类的用法总结
    SourceInsight中 加namespace宏后,无法跳转问题解决
    ubuntu 12.04安装vmtools 问题解决
    Prolific PL2303 usb 转串口Win8 Win8.1驱动
    大津法阈值法代码
    opencv常用函数备忘
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12433718.html
Copyright © 2011-2022 走看看