zoukankan      html  css  js  c++  java
  • 洛谷 P5339 [TJOI2019]唱、跳、rap和篮球

    大中锋的学院要组织学生参观博物馆,要求学生们在博物馆中排成一队进行参观。他的同学可以分为四类:一部分最喜欢唱、一部分最喜欢跳、一部分最喜欢rap,还有一部分最喜欢篮球。如果队列中(k),(k + 1),(k + 2),(k + 3)位置上的同学依次,最喜欢唱、最喜欢跳、最喜欢rap、最喜欢篮球,那么他们就会聚在一起讨论蔡徐坤。大中锋不希望这种事情发生,因为这会使得队伍显得很乱。大中锋想知道有多少种排队的方法,不会有学生聚在一起讨论蔡徐坤。两个学生队伍被认为是不同的,当且仅当两个队伍中至少有一个位置上的学生的喜好不同。由于合法的队伍可能会有很多种,种类数对(998244353)取模。

    (n le 1000)(a, b, c, d le 500)


    看起来非常可以容斥啊,所以直接考虑容斥,设 (f_i) 表示至少有 (i) 组人在讨论的方案数, (g_i) 表示恰好有 (i) 组人在讨论的方案数。

    因为这个是无标号的,所以有容斥式子:

    [g_i=sum_{j=i}^m(-1)^{j-i}f_j ]

    (m) 是最多可以有几组人,那么 (ans = g_0)

    然后计算 (f_i) ,我们先选出 (i) 组人,然后剩下的四种颜色进行排列,设 (S(a,b,c,d,n)) 表示四种颜色的数量,要选出来 (n) 个组成排列的方案,然后加上 (i) 组人我们有 (n-3i) 个位置,对于每一组人要从这里头选一个位置放上,所以这样选的方案是 (n-3ichoose i) ,于是就可以这么计算 (f_i)

    [f_i={n-3ichoose i} imes S(a-i,b-i,c-i,d-i,n-4i) ]

    然后考虑如何计算 (S) ,我们可以对每一种颜色写出 EGF ,因为无标号,所以就是 (sum_{i=0}^{co}frac{x^i}{i!})(co) 就是一种颜色的个数,然后把这四个 EGF ,做卷积就可以计算出来了。

    复杂度是 (O(n^2log n))

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 2e3;
    const int M = 2e4;
    const int p = 998244353;
    using namespace std;
    int n,a,b,c,d,m,f[N + 5],fac[N + 5],inv[N + 5],ans,G[M + 5][2],rev[M + 5],maxn,lg,A[M + 5],B[M + 5];
    int C(int n,int m)
    {
        return 1ll * fac[n] * inv[n - m] % p * inv[m] % p;
    }
    int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
    void prework(int n)
    {
        lg = 0,maxn = 1;
        while (maxn < n)
            maxn <<= 1,lg++;
        for (int i = 0;i < maxn;i++)
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
    }
    void ntt(int *a,int typ)
    {
        for (int i = 0;i < maxn;i++)
            if (i < rev[i])
                swap(a[i],a[rev[i]]);
        for (int i = 1;i < maxn;i <<= 1)
            for (int j = 0;j < maxn;j += i << 1)
                for (int k = 0;k < i;k++)
                {
                    int x = a[j + k],t = 1ll * G[k + i][typ] * a[j + k + i] % p;
                    a[j + k] = (x + t) % p;
                    a[j + k + i] = (x - t) % p;
                }
        if (!typ)
        {
            int in = mypow(maxn,p - 2);
            for (int i = 0;i < maxn;i++)
                a[i] = 1ll * a[i] * in % p;
        }
    }
    int S(int a,int b,int c,int d,int n)
    {
        prework((a + b + c + d + 4) * 2);
        for (int i = 0;i < maxn;i++)
            A[i] = B[i] = 0;
        for (int i = 0;i <= a;i++)
            A[i] = inv[i];
        for (int i = 0;i <= b;i++)
            B[i] = inv[i];
        ntt(A,1);
        ntt(B,1);
        for (int i = 0;i < maxn;i++)
            A[i] = 1ll * A[i] * B[i] % p;
        for (int i = 0;i < maxn;i++)
            B[i] = 0;
        for (int i = 0;i <= c;i++)
            B[i] = inv[i];
        ntt(B,1);
        for (int i = 0;i < maxn;i++)
            A[i] = 1ll * A[i] * B[i] % p;
        for (int i = 0;i < maxn;i++)
            B[i] = 0;
        for (int i = 0;i <= d;i++)
            B[i] = inv[i];
        ntt(B,1);
        for (int i = 0;i < maxn;i++)
            A[i] = 1ll * A[i] * B[i] % p;
        ntt(A,0);
        return 1ll * fac[n] * A[n] % p;
    }
    int main()
    {
        cin>>n>>a>>b>>c>>d;
        m = min(min(min(min(a,b),c),d),n / 4);
        fac[0] = 1;
        for (int i = 1;i <= N;i++)
            fac[i] = 1ll * fac[i - 1] * i % p;
        inv[1] = 1;
        for (int i = 2;i <= N;i++)
            inv[i] = 1ll * inv[p % i] * (p - p / i) % p;
        inv[0] = 1;
        for (int i = 1;i <= N;i++)
            inv[i] = 1ll * inv[i - 1] * inv[i] % p;
        prework((a + b + c + d + 4) * 2);
        for (int i = 1;i < maxn;i <<= 1)
        {
            int g1 = mypow(3,(p - 1) / (i << 1)),g2 = mypow(mypow(3,p - 2),(p - 1) / (i << 1));
            G[i][0] = G[i][1] = 1;
            for (int j = 1;j < i;j++)
                G[i + j][1] = 1ll * G[i + j - 1][1] * g1 % p,G[i + j][0] = 1ll * G[i + j - 1][0] * g2 % p;
        }
        for (int i = 0;i <= m;i++)
            f[i] = 1ll * C(n - 3 * i,i) * S(a - i,b - i,c - i,d - i,n - 4 * i) % p;
        for (int i = 0;i <= m;i++)
            ans += ((i & 1) ? -1 : 1) * f[i],ans %= p;
        cout<<(ans + p) % p<<endl;
        return 0;
    }
    
  • 相关阅读:
    hadoop wordcount
    hadoop map reduce 实例wordcount的使用
    玉髓
    数据类型检测的四种方式
    天猫前端招聘要求
    正则示例1
    字面量和实例创建的区别
    正则表达式
    面试题1
    this关键字
  • 原文地址:https://www.cnblogs.com/sdlang/p/14283167.html
Copyright © 2011-2022 走看看