NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)
题解:
我果然是不擅长分类讨论,心态被搞崩了。
注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍。
先考虑个大概:
考虑若存在\(x,x-1,…,2\)(有序)这样的,且1要么不出现,要么出现在2的左边,那么\(a[1]=\sum_{i=1}^x a[i]\)。
同样,若存在\(y,y+1,…,n\),且1要么不出现,要么出现在n的左边,那么\(a[1]=a[1]+\sum_{i=y}^n a[i]\)。
开始讨论:
1.1没有出现,直接枚举x,求出最大的y的满足\(sum>=K\),现在大概要求x要恰好,y要至少。
至少好算,恰好的话考虑用至少x减去至少x+1。
2.1出现了,1的右边只有2,,n要么不出现,要么出现在1的左边,注意这种情况下\(y->n\)的和依然会被加进a[1],同样枚举x,求出最大的y,然后我们可以列出一个限制树,若\(j\)必须在\(i\)的左边,\(link(i,j)\),根据CTS2019氪金手游那题,概率是\(\prod{1 \over siz}\),乘上总方案数便是可行的方案数。
3.把上种情况的2、n互换,求法类似。
4.1出现了,2和n都在1的右边,注意这种情况\(a[1]\)会被加两遍,同样枚举x,求最大的y,然后列出限制树,发现并不是外向树,有一条内向边,那么直接把这条边容斥即可。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 998244353;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const int N = 2e5 + 5;
int T, n, m, K;
ll a[N];
ll fac[N], nf[N], ni[N];
ll C(int n, int m) {
return n < m || n < 0 || m < 0 ? 0 : fac[n] * nf[m] % mo * nf[n - m] % mo;
}
ll P(int n, int m) {
return n < m || n < 0 || m < 0 ? 0 : fac[n] * nf[n - m] % mo;
}
ll p[N], q[N];
ll ans;
ll ca1(int x, int z) {
return (x + z <= m) ? (C(m, x) * C(m - x, z) % mo * P(n - 1 - x - z, m - x - z) % mo) : 0;
}
void calc1() {
int y = n + 1;
fd(x, m + 1, 1) {
while(y > 1 && p[x] + q[y] < K) y --;
if(p[x] + q[y] < K) continue;
int z = n - y + 1;
ans += ca1(x - 1, z);
ans -= ca1(x, z);
}
ans %= mo;
}
ll ca2(int x, int z) {
if(x + z > m) return 0;
return fac[m] * C(n - (x + z), m - (x + z)) % mo * nf[x - 2] % mo * nf[z + 1] % mo * ni[x + z] % mo;
}
void calc2() {
int y = n + 1;
fd(x, m, 2) {
while(y > 1 && p[x] + q[y] < K) y --;
if(p[x] + q[y] < K) continue;
int z = n - y + 1;
if(z > 0) {
ans += ca2(x, z);
ans -= ca2(x + 1, z);
} else {
n --;
ans += ca2(x, z);
ans -= ca2(x + 1, z);
n ++;
ans += ca2(x, 1);
ans -= ca2(x + 1, 1);
}
}
}
void calc3() {
int z = 1;
fo(y, n - m + 1, n) {
while(z < n && p[z] + q[y] < K) z ++;
if(p[z] + q[y] < K) continue;
int x = n - y + 2;
if(z > 1) {
ans += ca2(x, z - 1);
ans -= ca2(x + 1, z - 1);
} else {
n --;
ans += ca2(x, z - 1);
ans -= ca2(x + 1, z - 1);
n ++;
ans += ca2(x, 1);
ans -= ca2(x + 1, 1);
}
}
}
ll ca4(int x, int z) {
if(x + z > m) return 0;
ll sum = nf[z] * nf[x - 2] % mo * ni[x] % mo;
sum = (sum - nf[z + 1] * nf[x - 2] % mo * ni[x + z] % mo + mo) % mo;
return C(n - (x + z), m - (x + z)) * fac[m] % mo * sum % mo;
}
void calc4() {
int y = n;
fd(x, m, 2) {
while(y > 1 && p[x] + q[y] + a[1] < K) y --;
if(p[x] + q[y] + a[1] < K) continue;
int z = n - y + 1;
ans += ca4(x, z);
ans -= ca4(x + 1, z);
}
}
int main() {
freopen("fake.in", "r", stdin);
freopen("fake.out", "w", stdout);
n = 2e5;
fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
nf[n] = ksm(fac[n], mo - 2); fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
fo(i, 1, n) ni[i] = ksm(i, mo - 2);
for(scanf("%d", &T); T; T --) {
scanf("%d %d %d", &n, &m, &K);
fo(i, 1, n) scanf("%lld", &a[i]);
if(K == 0) {
pp("1\n"); continue;
}
q[n + 1] = p[0] = 0;
fo(i, 1, n) p[i] = p[i - 1] + a[i];
fd(i, n, 1) q[i] = q[i + 1] + a[i];
ans = 0;
calc1();
calc2();
calc3();
calc4();
ans = (ans % mo + mo) * ksm(P(n, m), mo - 2) % mo;
pp("%lld\n", ans);
}
}
NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)的更多相关文章
- 6364. 【NOIP2019模拟2019.9.20】养马
题目描述 题解 一种显然的水法:max(0,-(点权-边权之和*2)) 这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值 考虑从子树往上推求出当前点的答案 设每棵子树从根往 ...
- 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)
题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...
- [JZOJ6359] 【NOIP2019模拟2019.9.15】小ω的树
题目 题目大意 给你一棵树,带点权和边权. 要你选择一个联通子图,使得点权和乘最小边权最大. 支持修改点权操作. 思考历程 显然,最先想到的当然是重构树了-- 重构树就是在做最大生成树的时候,当两个联 ...
- 【2019.8.8 慈溪模拟赛 T2】query(query)(分治+分类讨论)
分治 首先,我们考虑分治处理此问题. 每次处理区间\([l,r]\)时,我们先处理完\([l,mid]\)和\([mid+1,r]\)两个区间的答案,然后我们再考虑计算左区间与右区间之间的答案. 处理 ...
- [JZOJ6075]【GDOI2019模拟2019.3.20】桥【DP】【线段树】
Description N,M<=100000,S,T<=1e9 Solution 首先可以感受一下,我们把街道看成一行,那么只有给出的2n个点的纵坐标是有用的,于是我们可以将坐标离散化至 ...
- 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋
题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...
- 6392. 【NOIP2019模拟2019.10.26】僵尸
题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...
- 6389. 【NOIP2019模拟2019.10.26】小w学图论
题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...
- 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...
随机推荐
- 【leetcode】395. Longest Substring with At Least K Repeating Characters
题目如下: 解题思路:题目要找出一段连续的子串内所有字符出现的次数必须要大于k,因此出现次数小于k的字符就一定不能出现,所以就可以以这些字符作为分隔符分割成多个子串,然后继续对子串递归,找出符合条件的 ...
- 阿里云移动研发平台EMAS,是如何连续5年安全护航双11的?
摘要: 阿里云作为阿里巴巴IT基础设施的基石,每年的双十一都面临前所未有的巨大技术挑战.阿里云的EMAS移动研发平台,连续5年支持双11,不仅保障了手机淘宝.支付宝这些阿里巴巴集团App的使用体验,也 ...
- OC学习篇之---循环引用问题
在之前的一片文章中,我们介绍了数组操作对象的时候引用问题以及自动释放池的概念: http://blog.csdn.net/jiangwei0910410003/article/details/4192 ...
- Service系统服务(六):rsync基本用法、rsync+SSH同步、配置rsync服务端、访问rsync共享资源、使用inotifywait工具、配置Web镜像同步、配置并验证Split分离解析
一.rsync基本用法 目标: 本例要求掌握远程同步的基本操作,使用rsync命令完成下列任务: 1> 将目录 /boot 同步到目录 /todir 下 2> 将目录 /boot 下的 ...
- 探索Redis设计与实现9:数据库redisDb与键过期删除策略
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- Unicode数据类型的是是非非(转)
转:http://cio.chinabyte.com/344/9002344.shtml 在SQL Server数据库中,数据类型主要分为两类,分别为Unicode数据类型与非Unicode数据类型. ...
- ICO和区块链区别
区块链项目众筹(ICO)浅析 2017-07-25 原创 Fintech科普大使 ICO是区块链初创公司项目融资的重要方式类似于Kickstarter众筹,但有不同之处(具体在下一节详述),可以避开传 ...
- centos 7 下升级自带 sqlite3
问题 在 centos 7 上面运行 django 2.2 开发服务器时出现: django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or ...
- 实验吧关于隐写术的writeUp(二)
0x01 Black Hole 1.下载文件后,发现打不开,放到kali中.用命令file 分析一下文件 root@trial:~/Documents# file blackhole.img blac ...
- 【Vue】---Vue.config常用配置项
一.前言 Vue-cli3 搭建的项目 相比较Vue-cli2界面相对较为简洁,之前的build和config文件夹不见了,那么应该如何配置 如webpack等的配呢? 二.基本配置 只需要在项目的根 ...