• CF1251F Red-White Fence


    多项式学习 Day 3.

    第一篇多项式题解 >_<

    思路

    注意到周长其实就是红板长度加上选的板子的数量。

    于是当我们确定了红板长度 (L) 和周长 (C) 之后,我们需要取出 (frac{C}{2}-L-1) 块白板。

    然后很恶心的是虽然板子不能一样长,但是可以在红板两侧各来一块相同长度的白板。

    于是我们发现一种颜色的白板超过两条和两条是等价的

    然后我们考虑两种特殊情况:

    • 所有白板都只有一条。

    这种情况下,我们可以先选 (j) 条,然后分别考虑每条放左边还是右边。

    如果从 (i) 种白板中选出 (j) 条,那么有 (2^jinom{i}{j}) 种方案。

    • 所有白板都有两条。

    我们让第一条代表放在左边,第二条代表放在右边。

    那么一种方案和选 (j) 条板子是一一对应的。

    那么如果从 (i) 种白板种选出 (j) 条,那么有 (inom{2i}{j}) 种方案。

    然后我们发现选出 (i) 条白板的过程可以拆解成选出 (j)只有一条的白板和 (i-j)有两条的白板。

    于是我们只需要把两部分拆开即可,先算出选出 (j)只有一条的白板和有两条的白板的方案数,然后卷积即可。

    注意到白板的长度要小于红板,所以要对于每块红版单独 ( ext{NTT}) 一次。

    代码

    //zhoukangyang AK IOI!
    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
       int s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    }
    const long long p=998244353;
    long long qp(long long x,int y)
    {
        long long res=1;
        for(long long now=x; y; now=now*now%p,y>>=1) if(y&1) res=res*now%p;
        return res;
    }
    long long A[6000003],B[6000003];
    int rev[6000003],N=1;
    void init()
    {
        int d=N>>1;
        rev[0]=0,rev[1]=N>>1;
        for(int i=2; i<=N; i<<=1)
        {
            d>>=1;
            for(int j=0; j<i; ++j) rev[i+j]=rev[j]|d;
        }
        return ;
    }
    void NTT(long long* F,int op)
    {
        for(int i=0; i<N; ++i) if(rev[i]>i) swap(F[i],F[rev[i]]);
        for(int len=2,M=1; len<=N; len<<=1,M<<=1)
        {
            long long w=qp(op?3:332748118,998244352/len);
            //omega(m,1)
            for(int l=0,r=len-1; l<=N; l+=len,r+=len)
            {
                long long w0=1;
                for(int i=l; i<l+M; ++i)
                {
                    long long x=(F[i]+w0*F[i+M]%p)%p,y=(F[i]+p-w0*F[i+M]%p)%p;
                    F[i]=x,F[i+M]=y,w0=w0*w%p;
                }
            }
        }
    }
    int cnt[1000003],b[13],q[1000003];
    long long ans[1000003];
    int t;
    void solve(int lim)
    {
    	int P=0,Q=0;
    	for(int i=1; i<lim; ++i) if(cnt[i]==1) ++P; else if(cnt[i]>=2) ++Q;
    	Q<<=1;
    	for(;N<=P+Q;N<<=1);
    	for(int i=0; i<N; ++i) A[i]=B[i]=0;
    	long long fz=1,fm=1;
        for(int i=0; i<=P; ++i,fz=fz*(P+1-i)%p,fm=fm*i%p) A[i]=fz*qp(fm,p-2)%p*qp(2,i)%p;
        fz=fm=1;
        for(int i=0; i<=Q; ++i,fz=fz*(Q+1-i)%p,fm=fm*i%p) B[i]=fz*qp(fm,p-2)%p;
        init();
        NTT(A,1),NTT(B,1);
        for(int i=0; i<N; ++i) A[i]=A[i]*B[i]%p;
        NTT(A,0);
        long long inv=qp(N,998244351);
        for(int i=0; i<N; ++i) A[i]=A[i]*inv%p;
        for(int j=1; j<=t; ++j) if(q[j]-lim>=0) ans[j]=(ans[j]+A[q[j]-lim])%p;
        return ;
    }
    signed main()
    {
        int n=read(),k=read();
        for(int i=1; i<=n; ++i) ++cnt[read()];
        for(int i=1; i<=k; ++i) b[i]=read();
        t=read();
        for(int i=1; i<=t; ++i) q[i]=(read()>>1)-1;
        for(int i=1; i<=k; ++i) solve(b[i]);
    	for(int i=1; i<=t; ++i) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    vue基础知识
    制作离线yum源
    mysql字符集
    confluence 容器版 搭建部署
    iptables和ipvs
    http状态码
    运维相关网站博客集合
    搭建nexus私有maven私服
    MySQL 常见错误代码说明
    nc(瑞士军刀)
  • 原文地址:https://www.cnblogs.com/dead-X/p/14274664.html
Copyright © 2020-2023  润新知