zoukankan      html  css  js  c++  java
  • bzoj5406: Gift

    全程膜拜 码得都要一样了。。

    对于这种数列置换的可以理解成多个环,而对于一个大小为d的环把顺序弄对要做d-1次

    总起来就是n-环数的次数 加上暴力30pt到手啦

    假如题目没有限制,那就是第一类斯特林数,因为点有序再乘一个所有点的全排列 又20pt到手啦,考场上就溜了

    先缩链,一条链只有头和尾是有用的

    现在考虑分情况讨论。如果我们让第一个数列的数字连向第二个数列的对应数字(或许这样理解环容易些),将有四种情况:上面是否有当前数字,下面是否有当前数字。给出的限制相当于提前先给了一些链

    假如用二进制表示,0没有1有会方便点

    对于11就不用管了,对于直接就是一个环的更不用管了,最后减一下直接是一个环的个数就好

    主要问题在01和10,这两个是类似的,容易发现它们是不能互接成链的(废话要不就成11了),处理一个就行了吧。处理10的情况

    我们先把出现10情况的数字个数处理出来

    设f[i]表示这些数字构成的环数为i的方案数

    当然这样的东西肯定是要上个容斥的,设g[i]是至少为i,要有g[i]=sigema(i~n)j f[j]*j的容斥系数

    这样g[x]=sigema(x^k)i C(k,i)*S1(i,x)*(m+k-i)^(k-i)

    k为10情况的数字个数,m为00情况的个数,含义为选i个数字,然后把它划分到x个环,剩下的k-i个10情况的数字可以选择接去其中一个状态为00的数字,连了边以后相当于一个10一个01,我们也可以看成一个11一个00,恰好抵消扔给00的情况自己处理,也可以接到一个未划分的或者不接,未划分的自己也会找其他的,不接就自环咯。因为选了就不能再选所以是降次幂

    考虑f对g的贡献,对于fd,对gx的贡献为C(d,x),意为d中选x个环给选中,于是g[i]=sigema(i~n)j f[j]*C(j,i),直接二项式反演即可

    00的情况就是20pt的做法

    as[x]=∑∑∑f(i)g(j)h(k)(i+j+k==x) 分别是10,01,00的情况

    做两次卷积,因为数据小那就不彂(fa)發(fa)闧(ta)了我不会NTT啊,直接暴力搞

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    
    #define rcy(x) ((x)%2==0?1:-1)
    using namespace std;
    typedef long long LL;
    const int _=100;
    const int maxn=2*1e3+_;
    const LL mod=998244353;
    
    LL C[maxn][maxn],S[maxn][maxn],A[maxn][maxn];//i的降j次幂 
    void yu()
    {
        C[0][0]=S[0][0]=A[0][0]=1;
        for(int i=1;i<maxn;i++)
        {
            C[i][0]=A[i][0]=1;
            for(int j=1;j<=i;j++)
                C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod,
                S[i][j]=(S[i-1][j-1]+(i-1)*S[i-1][j])%mod,
                A[i][j]=A[i][j-1]*(i-j+1)%mod;
        }
    }
    
    //------------------------------------------def-------------------------------------------------------
    
    bool vis[maxn*2];int n,nxt[maxn*2],cnt[4];//0-x,x-0,x-x,0-0
    void dfs(int x,int st)
    {
        vis[x]=true;
        if(nxt[x]==0)
        {
            if(x>n&&st>n)cnt[3]++;
            else if(x<=n&&st>n)cnt[0]++;
            else if(x>n&&st<=n)cnt[1]++;
        }
        else
        {
            if(!vis[nxt[x]])dfs(nxt[x],st);
            else cnt[2]++;
        }
    }
    
    //-------------------------------------------分类讨论---------------------------------------------- 
    
    void calc(LL *u,int k)
    {
        for(int x=0;x<=k;x++)
            for(int i=x;i<=k;i++)
                u[x]=(u[x]+C[k][i]*S[i][x]%mod*A[cnt[3]+k-i][k-i])%mod;
        
        for(int i=0;i<=k;i++)
        {
            for(int j=i+1;j<=k;j++)
                u[i]=(u[i]+rcy(j-i)*u[j]*C[j][i])%mod;
            u[i]=(u[i]+mod)%mod;
        }
    }
    LL f[maxn],g[maxn],h[maxn],as[maxn];
    void solve()
    {
        calc(f,cnt[0]),calc(g,cnt[1]);
        
        for(int i=0;i<=n;i++)
            for(int j=0;j<=i;j++)
                h[i]=(h[i]+f[j]*g[i-j])%mod;        
        for(int i=0;i<=n;i++)
            for(int j=0;j<=i;j++)
                as[i]=(as[i]+h[j]*S[cnt[3]][i-j])%mod;
                
        for(int i=0;i<=n;i++)as[i]=as[i]*A[cnt[3]][cnt[3]]%mod;
    }
    
    //--------------------------------------------solve-------------------------------------------------
    
    int a[maxn],b[maxn]; bool ru[maxn*2];
    int main()
    {
        freopen("gift.in","r",stdin);
        freopen("gift.out","w",stdout);
        yu();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        
        memset(vis,true,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            if(a[i]==0)a[i]=i+n;
            if(b[i]==0)b[i]=i+n;
            vis[a[i]]=vis[b[i]]=false;
            if(a[i]<=n||b[i]<=n)
                nxt[a[i]]=b[i],ru[b[i]]=true;
        }
        for(int i=1;i<=2*n;i++)
            if(!vis[i]&&!ru[i])dfs(i,i);
        for(int i=1;i<=2*n;i++)
            if(!vis[i])dfs(i,i);
            
        solve();
        for(int i=0;i<n;i++)
            printf("%lld ",n-cnt[2]-i>=0?as[n-cnt[2]-i]:0);
        puts("");
        return 0;
    }
  • 相关阅读:
    什么是MIME
    bit/byte/英文字符/汉字之间的换算及java八大基本数据类型的占字节数
    js 上传文件大小检查
    java.toString() ,(String),String.valueOf的区别
    java 下载文件的样例
    回调函数分析
    IO流详析
    各个秒之间的换算率
    内边距:
    Less-6【报错+BOOL类型】
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10336882.html
Copyright © 2011-2022 走看看