题解-CTS2019随机立方体
problem
题意概要:一个 \(n\times m\times l\) 的立方体,立方体中每个格子上都有一个数,如果某个格子上的数比三维坐标中至少有一维相同的其他格子上的数都要大的话,我们就称它是极大的。将 \(n\times m\times l\) 的排列随机填入这些格子,求恰有 \(k\) 个极大的数的概率。\(T\) 组数据。
\(T\le 10,\ 1\le n,m,l\le 5\times 10^6,\ 1\le k \le 100\),时限 \(5s\)
Solution
为啥CTS比APIO难这多?我果然还是不会数数呐
根据这一个月来的数数经验……发现:
- 求答案为 \(k\) (权值)的题:应该是转换成 “答案小于等于 \(k\)” 减去 “答案小于等于 \(k-1\)”。
- 求恰好 \(k\) 个(数量)的题:应该是转换成 “至少有 \(k\) 个”,再利用二项式反演得到答案。
所以这里设 \(f[i]\) 表示至少有 \(i\) 个极大值的概率,答案即为:
\]
问题转换成求 \(f[i]\)。
首先选出这 \(i\) 个确定的极大值的坐标,系数为:\(P_n^iP_m^iP_l^i\)(考虑顺序,后边要用到)
定义一个坐标 \((x_0,y_0,z_0)\) 的控制范围为 三个平面 \(x=x_0,y=y_0,z=z_0\) 的并(所以极大值的定义即为:该点权值 为 其控制范围上点的权值最大值)
问题转化为求这 \(i\) 个坐标的控制范围的并内,有多少种安排数字顺序(不是权值而是大小关系,因为目前已经选出了这些坐标,并且现在要求的是概率,而非方案数)的方法,使得对于每个选定的坐标,其都为自己控制范围内的最大值。
直接考虑这个问题不好考虑,需要找到突破口,而这里的突破口就是 “这些控制范围的并内,最大值一定是一个极大值”。由于我们在选出这 \(i\) 个坐标的时候,已经考虑了顺序问题,所以若 这\(i\)个极大值控制范围的并 大小为 \(S_i\),则这件事情发生的概率为 \(\frac 1{S_i}\),并且发生这件事情后,所有只被这个极大值控制的点都没用了,则将问题转化为选出 \(i-1\) 个坐标的情况,如此递归,计算得到的权值为 \(\prod_{j=1}^i\frac 1{S_j}\)
至于如何计算 \(S_i\),可以发现取全局减多余可得 \(S_i=nml-(n-i)(m-i)(l-i)\),或是直接考虑容斥 \(S_i=(nm+nl+ml)i-(n+m+l)i^2+i^3\)
汇总一下,得到:
=P_n^iP_m^iP_l^i\prod_{j=1}^i\frac 1{nml-(n-i)(m-i)(l-i)}\\
Ans=\sum_{i=k}^{\min\{n,m,l\}}(-1)^{i-k}\binom ikf[i]\\
=\sum_{i=k}^{\min\{n,m,l\}}(-1)^{i-k}\binom ikP_n^iP_m^iP_l^i\prod_{j=1}^i\frac 1{nml-(n-i)(m-i)(l-i)}
\]
这个式子是线性的,但由于后头那个 \(\prod\) 需要求逆元,所以复杂度为 \(O(\min\{n,m,l\}\log p)\),如此能过 \(80\)。
考虑到这个东西实际上是要求每一个前缀积的逆元,和求阶乘逆元类似,可以先求出整个前缀积的逆元,再从后面往前乘,复杂度 \(O(\min\{n,m,l\}+\log p)\)
设:
\[a_i=nml-(n-i)(m-i)(l-i)\\
b_i=\prod_{j=1}^ia_j\\
c_i=\frac 1{b_i}
\]可以 \(O(1)\) 得到 \(a_i\),\(O(n)\) 得到 \(b_i\),\(O(\log p)\) 得到 \(c_n=\frac 1{b_n}\),\(O(n)\) 得到 \(c_i=c_{i+1}\cdot a_{i+1}\)
Code
//loj-3119
#include <cstdio>
typedef long long ll;
const int N = 5001010, p = 998244353;
int fac[N], ifac[N];
int coe[N], h[N], ih[N];
int n, m, l, k;
inline int qpow(int A, int B) {
int res = 1; while(B) {
if(B&1) res = (ll)res * A%p;
A = (ll)A * A%p, B >>= 1;
} return res;
}
int main() {
fac[0] = 1;
for(int i=1;i<N;++i) fac[i] = (ll)fac[i-1] * i%p;
ifac[N-1] = qpow(fac[N-1], p-2);
for(int i=N-1;i;--i) ifac[i-1] = (ll)ifac[i] * i%p;
int T; scanf("%d",&T);
while(T--) {
scanf("%d%d%d%d", &n, &m, &l, &k);
if(n > m) n ^= m, m ^= n, n ^= m;
if(n > l) n ^= l, l ^= n, n ^= l;
const int s2 = ((ll)n*m + (ll)m*l + (ll)n*l)%p, s1 = n+m+l;
for(int i=h[0]=1;i<=n;++i) {
coe[i] = (s2 - (ll)s1 * i + (ll)i*i + (ll)p*p)%p * i%p;
h[i] = (ll)h[i-1] * coe[i]%p;
}
ih[n] = qpow(h[n], p-2);
for(int i=n;i;--i) ih[i-1] = (ll)ih[i] * coe[i]%p;
const int nml_k = (ll)fac[n] * fac[m]%p * fac[l]%p * ifac[k]%p;
int Ans = 0;
for(int i=k;i<=n;++i) {
int vl = (ll)nml_k * fac[i]%p * ifac[i-k]%p * ifac[n-i]%p * ifac[m-i]%p * ifac[l-i]%p;
vl = (ll)vl * ih[i]%p;
if(i-k&1) vl = p - vl;
(Ans += vl) >= p && (Ans -= p);
}
printf("%d\n", Ans);
}
return 0;
}
题解-CTS2019随机立方体的更多相关文章
- 【题解】Luogu P5400 [CTS2019]随机立方体
原题传送门 毒瘤计数题 我们设\(dp_i\)表示至少有\(i\)个极大数字的概率,\(ans_i\)表示恰好有\(i\)个极大数的概率,\(mi=Min(n,m,l)\) 易知: \[dp_i=\s ...
- LOJ3119 CTS2019 随机立方体 概率、容斥、二项式反演
传送门 为了方便我们设\(N\)是\(N,M,L\)中的最小值,某一个位置\((x,y,z)\)所控制的位置为集合\(\{(a,b,c) \mid a = x \text{或} b = y \text ...
- [LOJ#3119][Luogu5400][CTS2019]随机立方体(容斥+DP)
https://www.cnblogs.com/cjyyb/p/10900993.html #include<cstdio> #include<algorithm> #defi ...
- Luogu5400 CTS2019随机立方体(容斥原理)
考虑容斥,计算至少有k个极大数的概率.不妨设这k个数对应的格子依次为(k,k,k)……(1,1,1).那么某一维坐标<=k的格子会对这些格子是否会成为极大数产生影响.先将这样的所有格子和一个数集 ...
- [CTS2019]随机立方体(容斥+组合数学)
这题七次方做法显然,但由于我太菜了,想了一会发现也就只会这么多,而且别的毫无头绪.发现直接做不行,那么,容斥! f[i]为至少i个极值的方案,然后这里需要一些辅助变量,a[i]表示选出i个三维坐标均不 ...
- 洛谷 P5400 - [CTS2019]随机立方体(组合数学+二项式反演)
洛谷题面传送门 二项式反演好题. 首先看到"恰好 \(k\) 个极大值点",我们可以套路地想到二项式反演,具体来说我们记 \(f_i\) 为钦定 \(i\) 个点为极大值点的方案数 ...
- 【CTS2019】随机立方体(容斥)
[CTS2019]随机立方体(容斥) 题面 LOJ 洛谷 题解 做这道题目的时候不难想到容斥的方面. 那么我们考虑怎么计算至少有\(k\)个极大值的方案数. 我们首先可以把\(k\)个极大值的位置给确 ...
- 「CTS2019 | CTSC2019」随机立方体 解题报告
「CTS2019 | CTSC2019」随机立方体 据说这是签到题,但是我计数学的实在有点差,这里认真说一说. 我们先考虑一些事实 如果我们在位置\((x_0,y_0,z_0)\)钦定了一个极大数\( ...
- 【loj3119】【CTS2019】随机立方体
题目 一个 $ n m l $ 的立方体等概率填入 $ 1-nml $ ; 定义一个位置是极大的当且仅当这个位置比三位坐标的至少一维与之相等的位置的值都大. 询问极大值恰好有\(k\)个的 ...
随机推荐
- response.getWriter().println和@ResponseBody的比较及同时使用(用于回调函数)
@RequestMapping(value = "/test", method = { RequestMethod.GET, RequestMethod.POST }) @Resp ...
- hibernate如何配置自动生成表
hibernate自动生成表有两种方法: 1.直接写代码,通过方法来创建数据库表. 2.通过 hibernate.cfg.xml配置标签来创建数据表. 下面依次实现: 1.直接写代码,通过方法来创建数 ...
- .gitignore忽略多层文件夹用**
一.写法 **/bin/Debug/ 前面的两个*号代表任意多层上级文件夹 需要 git 1.8.2 及其以上的版本才支持 如何查看当前版本并且升级(windows) 二.如何升级 git是2.14. ...
- linux内核是在哪里创建1号进程的?
1. 请看rest_init的完整代码(不看也没关系,内核版本为5.2, init/main.c) noinline void __ref rest_init(void) { struct task_ ...
- Python3基础 内置函数 id
Python : 3.7.3 OS : Ubuntu 18.04.2 LTS IDE : pycharm-community-2019.1.3 ...
- java-mybaits-016-mybatis知识点StatementType
1.statementType 在mapper文件中可以使用statementType标记使用什么的对象操作SQL语句. statementType:标记操作SQL的对象 要实现动态传入表名.列名,需 ...
- Angular常用命令:
新建项目: ng new angualrdermo08 --skip-install 创建需要的组件: ng g component home
- springboot启动提示连接mysql报错:java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
如题,启动springboot报错: -- :: --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized wi ...
- 【PHP】 解决array_filter会过滤0 false的问题
定义和用法 array_filter() 函数用回调函数过滤数组中的元素. 该函数把输入数组中的每个键值传给回调函数.如果回调函数返回 true,则把输入数组中的当前键值返回给结果数组.数组键名保持不 ...
- [Scikit-learn] 1.4 Support Vector Regression
SVM算法 既可用于回归问题,比如SVR(Support Vector Regression,支持向量回归) 也可以用于分类问题,比如SVC(Support Vector Classification ...