[TJOI2019]唱、跳、rap和篮球(指数型生成函数+NTT+卷积)

文章目录

  • 题目
  • 题解
  • code1(NTT)
  • code2(EGF+卷积)

在这里插入图片描述

题目

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

输入格式
输入数据只有一行。每行5个整数,第一个整数n,代表大中锋的学院要组织多少人去参观博物馆。接下来四个整数a、b、c、d,分别代表学生中最喜欢唱的人数、最喜欢跳的人数、最喜欢rap的人数和最喜欢篮球的人数。保证a+b+c+d≥na+b+c+d \ge na+b+c+dn

输出格式
每组数据输出一个整数,代表你可以安排出多少种不同的学生队伍,使得队伍中没有学生聚在一起讨论蔡徐坤。结果对998244353998244353998244353取模。

输入输出样例
输入
4 4 3 2 1
输出
174

输入
996 208 221 132 442
输出
442572391

说明/提示
对于20%的数据,有n=a=b=c=d≤500n=a=b=c=d\le500n=a=b=c=d500
对于100%的数据,有n≤1000n \le 1000n1000a,b,c,d≤500a, b, c, d \le 500a,b,c,d500

题解

考虑枚举有iii堆人在讨论cxk小姐姐,那么被cxk迷倒的人就有4i4i4i个,且每一堆人是挨在一起的,
所以我们可以把这4i4i4i个人缩成iii个群体,每一个群体可以展开成为444
那么现在就只用考虑剩下的n−3in-3in3i人,放置的方案数就是Cn−3iiC_{n-3i}^iCn3ii
简单用整体法证明一下:
n−3in-3in3i人中,要选iii个拿来讨论,n−4in-4in4i个不讨论,方案数是对应的Cn−3ii=Cn−3in−4iC_{n-3i}^i=C_{n-3i}^{n-4i}Cn3ii=Cn3in4i
也可以理解为在n−3in-3in3i个空格里面找iii个起点开始讨论小姐姐


接着枚举好了iii及它们可能出现的地方Cn−3iiC_{n-3i}^iCn3ii,我们就要去考虑剩下n−4in-4in4i人的排列,可以乱来
(n−4i)!(n-4i)!(n4i)!
但是attentionattentionattention,如果看了我的上一篇指数型生成函数专练,就会与这里有一点相通
题目说的方案数不同的要求是至少有一个位置上的学生的喜好不同,而不是学生本人不同
所以我们要除掉喜好篮球,跳舞,唱歌,rap本身内部的乱拍,因为从爱好上来看是看不出来排列不同的
a,b,c,da,b,c,da,b,c,d分别代表学生中最喜欢唱的人数、最喜欢跳的人数、最喜欢rap的人数和最喜欢篮球的总人数,我们考虑的是剩下的不讨论cxk姐姐的学生乱排,所以要剪掉外层所枚举的去参与讨论的人数
(n−4i)!(a−i)!(n−i)!(c−i)!(d−i)!\frac{(n-4i)!}{(a-i)!(n-i)!(c-i)!(d-i)!}(ai)!(ni)!(ci)!(di)!(n4i)!


最后写出每种喜好的生成函数,以喜欢篮球的人为例:
∑i=0cxii!\sum_{i=0}^{c}\frac{x^i}{i!}i=0ci!xi
把四种爱好卷起来,卷出最后乘积的第n−4in-4in4i项就是我们需要除掉的东西,乘上(n−4i)!(n-4i)!(n4i)!就是真正的乱排数


因为带取模,所以是用NTTNTTNTT跑,除的话就要变成乘逆元,所以我们可以在卷的时候就直接卷逆元

但是我们又发现虽然假设的是iii堆人在讨论,但是统计答案的时候却把≥i\ge ii堆人讨论的情况都统计了
而且当统计i=1i=1i=1时,会算两遍至少两堆人讨论的方案,三遍至少三堆人讨论的方案…在统计i=2i=2i=2时,会算三遍至少三堆人讨论的方案…
当统计iii的方案时,会多算CjiC_j^iCji次至少jjj堆人讨论的方案,所以我们可以用容斥来解决


总结一下答案应该是
∑i=0min(−1)i∗Cn−3ii∗(n−4i)!(a−i)!(n−i)!(c−i)!(d−i)!\sum_{i=0}^{min}(-1)^i*C_{n-3i}^i*\frac{(n-4i)!}{(a-i)!(n-i)!(c-i)!(d-i)!}i=0min(1)iCn3ii(ai)!(ni)!(ci)!(di)!(n4i)!
在这里插入图片描述

code1(NTT)

#include <cstdio>
#include <iostream>
using namespace std;
#define mod 998244353
#define LL long long
#define MAXN 10005
int n, anum, bnum, cnum, dnum;
LL pi, ni, result;
LL a[MAXN], b[MAXN], c[MAXN], d[MAXN], rev[MAXN], fac[MAXN], Invfac[MAXN];LL qkpow ( LL x, LL y ) {LL ans = 1;while ( y ) {if ( y & 1 )ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}LL C ( int n, int m ) {return fac[n] * Invfac[m] % mod * Invfac[n - m] % mod;
}void NTT ( LL *c, LL limit, LL f ) {for ( LL i = 0;i < limit;i ++ )if ( i < rev[i] )swap ( c[i], c[rev[i]] );for ( LL i = 1;i < limit;i <<= 1 ) {LL omega = qkpow ( f == 1 ? pi : ni, ( mod - 1 ) / ( i << 1 ) );for ( LL j = 0;j < limit;j += ( i << 1 ) ) {LL w = 1;for ( LL k = 0;k < i;k ++, w = w * omega % mod ) {LL x = c[k + j], y = w * c[i + j + k] % mod;c[k + j] = ( x + y ) % mod;c[k + j + i] = ( x - y + mod ) % mod;}}}LL inv = qkpow ( limit, mod - 2 );if ( f == -1 )for ( LL i = 0;i < limit;i ++ )c[i] = c[i] * inv % mod;
}void init () {Invfac[0] = fac[0] = 1;for ( int i = 1;i <= n;i ++ )fac[i] = fac[i - 1] * i % mod;Invfac[n] = qkpow ( fac[n], mod - 2 );for ( int i = n - 1;i;i -- )Invfac[i] = Invfac[i + 1] * ( i + 1 ) % mod;
}LL solve ( int n, int A, int B, int C, int D ) {LL len = 1, l = 0;while ( len < ( ( A + B + C + D ) << 1 ) ) {len <<= 1;l ++;}for ( LL i = 0;i < len;i ++ )rev[i] = ( rev[i >> 1] >> 1 ) | ( ( i & 1 ) << ( l - 1 ) );for ( int i = 0;i < len;i ++ )a[i] = ( i <= A ? Invfac[i] : 0 );for ( int i = 0;i < len;i ++ )b[i] = ( i <= B ? Invfac[i] : 0 );for ( int i = 0;i < len;i ++ )c[i] = ( i <= C ? Invfac[i] : 0 );for ( int i = 0;i < len;i ++ )d[i] = ( i <= D ? Invfac[i] : 0 );NTT ( a, len, 1 );NTT ( b, len, 1 );NTT ( c, len, 1 );NTT ( d, len, 1 );for ( int i = 0;i < len;i ++ )a[i] = a[i] * b[i] % mod * c[i] % mod * d[i] % mod;NTT ( a, len, -1 );return a[n] * fac[n] % mod;
}int main() {pi = 3;ni = mod / pi + 1;scanf ( "%d %d %d %d %d", &n, &anum, &bnum, &cnum, &dnum );init();int k = min ( min ( min ( min ( anum, bnum ), cnum ), dnum ), n / 4 );anum -= k;bnum -= k;cnum -= k;dnum -= k;result = 0;for ( k;k >= 0;k -- ) {LL tmp = C ( n - 3 * k, k ) % mod * solve ( n - 4 * k, anum, bnum, cnum, dnum ) % mod;anum ++;bnum ++;cnum ++;dnum ++;result = ( result + ( ( k & 1 ) ? mod - tmp : tmp ) ) % mod;}printf ( "%lld\n", result );return 0;
}

code2(EGF+卷积)

#include <cstdio>
#include <iostream>
using namespace std;
#define mod 998244353
#define LL long long
#define MAXN 1005
int n, a, b, c, d;
LL result;
LL foldAB[MAXN], foldCD[MAXN], fac[MAXN], Invfac[MAXN];LL qkpow ( LL x, LL y ) {LL ans = 1;while ( y ) {if ( y & 1 )ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}LL C ( int n, int m ) {return fac[n] * Invfac[m] % mod * Invfac[n - m] % mod;
}void Fac () {Invfac[0] = fac[0] = 1;for ( int i = 1;i <= n;i ++ )fac[i] = fac[i - 1] * i % mod;Invfac[n] = qkpow ( fac[n], mod - 2 );for ( int i = n - 1;i;i -- )Invfac[i] = Invfac[i + 1] * ( i + 1 ) % mod;
}int main() {scanf ( "%d %d %d %d %d", &n, &a, &b, &c, &d );Fac();int k = min ( min ( min ( min ( a, b ), c ), d), n / 4 );a -= k;b -= k;c -= k;d -= k;for ( int i = 0;i <= a;i ++ )for ( int j = 0;j <= b;j ++ )foldAB[i + j] = ( foldAB[i + j] + Invfac[i] * Invfac[j] % mod ) % mod;for ( int i = 0;i <= c;i ++ )for ( int j = 0;j <= d;j ++ )foldCD[i + j] = ( foldCD[i + j] + Invfac[i] * Invfac[j] % mod ) % mod;result = 0;for ( k;k >= 0;k -- ) {LL ans = 0;int tp = n - 4 * k;for ( int i = 0;i <= tp;i ++ )ans = ( ans + foldAB[i] * foldCD[tp - i] % mod ) % mod;ans = ans * fac[tp] % mod * C ( n - k * 3, k ) % mod;result = ( result + ( ( k & 1 ) ? mod - ans : ans ) ) % mod;a ++;b ++;c ++;d ++;for ( int i = 0;i <= a;i ++ )foldAB[i + b] = ( foldAB[i + b] + Invfac[i] * Invfac[b] % mod ) % mod;for ( int i = 0;i <= b;i ++ )foldAB[i + a] = ( foldAB[i + a] + Invfac[i] * Invfac[a] % mod ) % mod;foldAB[a + b] = ( foldAB[a + b] - Invfac[a] * Invfac[b] % mod + mod ) % mod;for ( int i = 0;i <= c;i ++ )foldCD[i + d] = ( foldCD[i + d] + Invfac[i] * Invfac[d] % mod ) % mod;for ( int i = 0;i <= d;i ++ )foldCD[i + c] = ( foldCD[i + c] + Invfac[i] * Invfac[c] % mod ) % mod;foldCD[c + d] = ( foldCD[c + d] - Invfac[c] * Invfac[d] % mod ) % mod;}printf ( "%lld\n", result );return 0;
} 

代码或者思路有任何问题欢迎评论
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数数题(计数类 DP)做题记录

数数题(计数类 DP)做题记录 CF1657E Star MST 我们称张无向完全图是美丽的当且仅当&#xff1a;所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和。 完全图点数为 \(n\)&#xff0c;边权 \(\in[1,k]\)&#xff0c;\(1\le n,k\le 250\)。 发现所有和 \(1\)…

Sum of Paths CodeForces - 1467D

Sum of Paths CodeForces - 1467D Tagscombinatorics dp math *2200 题意&#xff1a; 定义一条好的路径&#xff0c;当且仅当从任意点出发之后恰好经过了 k 次移动&#xff0c;定义这条路径的权值为经过点权值的总和(可重)&#xff0c;进行 q 次修改&#xff0c;每次将ak 改…

[矩阵乘法/快速幂专题]Arc of Dream,Recursive sequence,233 Matrix,Training little cats

矩阵快速幂习题复习矩阵乘法及快速幂模板乘法模板快速幂模板T1&#xff1a;Arc of Dream题目题解codeT2&#xff1a;Recursive sequence题目题解codeT3&#xff1a;233 Matrix题目题解codeT4&#xff1a;Training little cats题目题解code做题的时候后悔没有保存过模板&#xf…

P3639-[APIO2013]道路费用【最小生成树】

正题 题目链接:https://www.luogu.com.cn/problem/P3639 题目大意 给出nnn个点mmm条有边权的无向图&#xff0c;然后再给出kkk条边权未定义的边&#xff0c;然后每个点有一个人数pip_ipi​。 现在要你给未确定的边权的边确定边权然后选出图的一棵最小生成树&#xff0c;之后…

你准备好了在云中工作吗?

前几天写了一篇文章 《云时代的.NET》&#xff0c;今天继续这个话题聊下云时代的技能。无服务器计算&#xff0c;容器化&#xff0c;云原生应用&#xff0c;DevOps&#xff0c;人工智能&#xff0c;机器学习以及混合云和多云解决方案等IT趋势正在成为主流或“新常态”。所有大小…

珂朵莉树(ODT)

珂朵莉树 ODT 主要内容 珂朵莉树是基于数据随机且有整体赋值操作而对序列操作的乱搞算法。 它的主要思想是用 set 维护若干个数值上相同的区间&#xff0c;并暴力处理其他询问。 建立 在 set 中&#xff0c;我们需要用结构体记录每个区间的信息&#xff1a; struct NODE {int l…

最长公共上升子序列(LCIS)

题意&#xff1a; 求最长公共上升子序列 题解&#xff1a; 最长公共上升子序列 最长公共子序列&#xff08;LCS&#xff09;与最长上升子序列&#xff08;LIS&#xff09; LCS核心代码&#xff1a; for(int i1;i<n;i){for(int j1;j<m;j){if(a[i]b[j])dp[i][j]max(dp[…

YBTOJ洛谷P1407:稳定婚姻(强连通分量)

文章目录题目描述解析代码题目描述 我们已知n对夫妻的婚姻状况&#xff0c;称第 i 对夫妻的男方为 Bi &#xff0c;女方为 Gi。 若某男 Bi 与某女 Gi 曾经交往过( i!j )&#xff0c;则当某方与其配偶&#xff08;即 Bi 与 Gi 或 Bj 与 Gj&#xff09;感情出现问题时&#xff…

[高斯消元及理论]线性方程组整数/浮点数,模线性方程组,异或方程组模板

文章目录理论线性方程组整数类型解线性方程组浮点类型解模线性方程组异或方程组高斯约旦消元约旦消元无解无穷解唯一解理论 高斯消元法&#xff0c;是线性代数规划中的一个算法&#xff0c;可用来为线性方程组求解。但其算法十分复杂&#xff0c;不常用于加减消元法&#xff0c…

eShopOnContainers 知多少[7]:Basket microservice

引言Basket microservice&#xff08;购物车微服务&#xff09;主要用于处理购物车的业务逻辑&#xff0c;包括&#xff1a;购物车商品的CRUD订阅商品价格更新事件&#xff0c;进行购物车商品同步处理购物车结算事件发布订阅订单成功创建事件&#xff0c;进行购物车的清空操作架…

P6805-[CEOI2020]春季大扫除【贪心,树链剖分,线段树】

正题 题目链接:https://www.luogu.com.cn/problem/P6805 题目大意 给出nnn个点的一棵树&#xff0c;qqq次独立的询问。每次询问会在一些节点上新增一些子节点&#xff0c;然后你每次可以选择两个为选择过的叶子节点然后覆盖它们的路径&#xff0c;要求在覆盖所有边的情况下使…

后缀数组 SA

后缀数组 SA 后缀树组(SA&#xff0c;suffix array)&#xff0c;用于处理字符串子串形成的结构。 处理子串的结构主要方式有&#xff1a;后缀数组 SA&#xff0c;后缀自动机 SAM&#xff0c;后缀树 ST。 后缀树和后缀自动机暂时决定咕咕咕&#xff0c;以后学习可以参考ix35 的字…

导弹防御系统

导弹防御系统 题意&#xff1a; 最少可以找到一直 严格单调 上升或者一直 严格单调 下降 题解&#xff1a; 第一反应是LIS&#xff0c;但是本题要求找一直上升或者一直下降的&#xff0c;LIS不能实现 但是我们还是从LIS下手&#xff0c;LIS中最核心的思想是能否将一个元素加…

STL:bitset用法详解

文章目录前言声明输入输出访问与修改位运算所谓bitset&#xff0c;就是bit组成的set &#xff08;逃&#xff09; 前言 bitset的诸多好处&#xff1a; 1.节约空间 2.增加一些新的功能 3.几乎没有副作用 4.有了123还不够吗&#xff01;&#xff1f; 当然&#xff0c;还有一个决…

微软热门开源项目及代码库地址

点击蓝字关注我这几年来&#xff0c;微软在开源与社区方向的努力与成就是全世界有目共睹的。微软的开源项目超过2000多个&#xff0c;挑了一些比较火热的给大家整理了一下。欢迎补充~Visual Studio Code非常流行的跨平台代码编辑器&#xff0c;提供全面的编辑和调试支持、可扩展…

P6846-[CEOI2019]Amusement Park【状压dp,FWT】

正题 题目链接:https://www.luogu.com.cn/problem/P6846 题目大意 给出nnn个点mmm条边的一张有向图&#xff0c;保证两个点之间最多只有一条边。现在你可以取反一些边使得图变为一张DAGDAGDAG&#xff0c;求所有方案的取反的边数和。 1≤n≤181\leq n\leq 181≤n≤18 解题思路…

CDQ 分治与整体二分

CDQ 分治与整体二分 CDQ 分治 主要是一种分治思想&#xff0c;常用于解决偏序问题。 例如三维偏序问题&#xff0c;我们采用的方法是先处理以第一关键字为区分的左区间、右区间内的答案&#xff0c;再处理左右区间互不干涉的答案。 四维偏序呢&#xff1f; 咕咕咕 整体二分 主要…

[树链剖分][SDOI 2011]染色,Housewife Wind

文章目录T1&#xff1a;Housewife Wind题目题解codeT2&#xff1a;染色题目题解code今天选择写这篇博客主要是为了告诉大家一个道理&#xff0c;数组比vectorvectorvector快太多了&#xff0c;我这两道题第一次都因为vectorvectorvector&#xff0c;TTT到飞起 T1&#xff1a;…

最长上升子序列模型

有两个模板&#xff1a; 最长上升子序列这类题目都是这俩变形而来 最长上升子序列模型 AcWing 1017. 怪盗基德的滑翔翼1120人打卡 AcWing 1014. 登山1094人打卡 AcWing 482. 合唱队形1069人打卡 AcWing 1012. 友好城市1040人打卡 AcWing 1016. 最大上升子序列和1048人打卡 AcWi…

YBTOJ:向量问题(线段树分治、凸包)

文章目录题目描述数据范围解析代码题目描述 你要维护一个向量集合&#xff0c;支持以下操作&#xff1a; 插入一个向量 。 删除插入的第 x 个向量。 查询当前集合与(x,y)(x,y)(x,y) 点积的最大值是多少。如果当前是空集输出0。 数据范围 n<2e5,x、y∈[1,2e6]n<2e5,x、y∈…