zoukankan      html  css  js  c++  java
  • loj3106「TJOI2019」唱、跳、rap 和篮球

    大中锋的学院要组织学生参观博物馆,要求学生们在博物馆中排成一队进行参观。
    他的同学可以分为四类:一部分最喜欢唱、一部分最喜欢跳、一部分最喜欢 rap,还有一部分最喜欢篮球。

    如果队列中 $k,k + 1,k + 2,k + 3$ 位置上的同学依次,最喜欢唱、最喜欢跳、最喜欢 rap、最喜欢篮球,那么他们就会聚在一起讨论蔡徐坤。
    大中锋不希望这种事情发生,因为这会使得队伍显得很乱。

    大中锋想知道有多少种排队的方法,不会有学生聚在一起讨论蔡徐坤。
    两个学生队伍被认为是不同的,当且仅当两个队伍中至少有一个位置上的学生的喜好不同。
    由于合法的队伍可能会有很多种,种类数对 $998244353$ 取模。


    Sol

    生成函数??


    我们考虑容斥。
    枚举有 $i$ 对讨论的。
    答案即 $(-1)^i imes C(n-3i,i) imes [剩下的人随便排的方案]$
    可以理解为把四个人压成一个人然后再组合。
    考虑怎么算剩下的人的方案。
    假设剩下$n$人要排,每种还剩$a,b,c,d$个。
    $sumlimits_{a}C(n,a)
    sumlimits_{b}C(n-a,b)
    sumlimits_{c}C(n-a-b,c)$
    剩下的给$d$。
    这个是$n^3$的。
    我们枚举AB用了$r$个,C则D用了$n-r$个。

    $sumlimits_{r=0}^{n}C(n,r)
    sumlimits_{i=max(0,r-b)}^{min(a,r)}C(r,i)
    sumlimits_{i=max(0,n-r-d)}^{min(c,n-r)}C(n-r,i)$
    这就是$n^2$的了。

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define mod 998244353
    #define ll long long
    #define maxn 1005
    using namespace std;
    int N,A,B,C,D; 
    ll z[maxn][maxn],s[maxn][maxn],ans;
    void init(){
        N=1000;
        for(int i=0;i<=N;i++){
            z[i][0]=s[i][0]=1;
            for(int j=1;j<=i;j++){
                z[i][j]=(z[i-1][j]+z[i-1][j-1])%mod;
                s[i][j]=(s[i][j-1]+z[i][j])%mod;
            }
        }
    }
    ll CC(int n,int m){
        return z[n][m];
    }
    ll Sum(int n,int l,int r){
        if(l>r)return 0;
        return s[n][r]-s[n][l-1];
    }
    ll get(int n,int a,int b,int c,int d){
        if(a<0||b<0||c<0||d<0)return 0;
        ll sum=0,s1,s2;
        for(int r=0;r<=n&&r<=a+b;r++){
            s1=Sum(r,max(0,r-b),min(a,r));
            s2=Sum(n-r,max(0,n-r-d),min(c,n-r));
            sum=(sum+CC(n,r)*s1%mod*s2%mod)%mod;
        }
        return sum;
    }
    int main(){
        init();
        scanf("%d%d%d%d%d",&N,&A,&B,&C,&D);
        A=min(A,N);B=min(B,N);C=min(C,N),D=min(D,N);
        for(int i=0;i*4<=N;i++){
            ll t=CC(N-3*i,i)*get(N-4*i,A-i,B-i,C-i,D-i)%mod;
            if(i&1)ans=ans-t;
            else ans=ans+t;
            ans%=mod;
        }
        ans=(ans+mod)%mod;
        cout<<ans<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    【转载】Unity 合理安排增量更新(热更新)
    COCOS2D 释放资源的最佳时机
    【转载】利用Unity自带的合图切割功能将合图切割成子图
    用GL画出人物的移动路径
    使用行为树(Behavior Tree)实现游戏AI
    C#学习笔记
    题目:给定一数组 例如:a = [1,2,3,5,2,1] 现用户提供一个数字 请返回用户所提供的数字的所有下标
    算法: 归并排序
    题目:给定两个有序数组,对其进行合并
    数据结构 顺序表实现优先队列 回顾练习
  • 原文地址:https://www.cnblogs.com/liankewei/p/12349876.html
Copyright © 2011-2022 走看看