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/ ...
随机推荐
- Selenium之WebDriverWait
转自https://blog.csdn.net/duzilonglove/article/details/78455051 Selenium之WebDriverWait用法
- 兼容新旧浏览器的flex写法
拷贝直接加类名即可 /* 定义 */ .flex-def { display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older W ...
- Andrdoid中对应用程序的行为拦截实现方式之----从Java层进行拦截
致谢: 感谢 简行之旅的这篇blog:http://blog.csdn.net/l173864930/article/details/38455951,这篇文章是参考这篇blog的进行一步一步操作的, ...
- 【Spring Boot】Spring Boot项目部署到外部Tomcat容器
一.修改项目打包方式为war包 修改pom.xml文件中packaging属性项 <packaging>war</packaging> 修改pom.xml文件增加一个依赖 &l ...
- HTML-参考手册: HTML 音频/视频
ylbtech-HTML-参考手册: HTML 音频/视频 1.返回顶部 1. HTML 音频/视频 DOM 参考手册 HTML5 DOM 为 <audio> 和 <video> ...
- Windows操作系统架构
用户态 用户态有四类组件,这四类组件都是以进程形式存在的,也就是说,它们都有自己的进程地址空间(其实就是一套页表). 1. System Support Processes 这些是固化的进程,也就是说 ...
- Device Drivers
Types of Device Drivers Windows可能会有User-mode的驱动,但是我们只关注Kernel-Mode的驱动. WDM Drivers WDM是一种驱动模型,是比较常用的 ...
- shell 读取配置文件的用法
https://blog.csdn.net/qq_36684665/article/details/81134179 亲测有用!
- 12.Jmeter 快速入门教程 -- 监控被测资源
写在前面的话, 作者认为jmeter的监控被测服务器资源只是基本可用, 还好习惯了linux的各种命令和工具,所以也基本不用担心什么了.但是有了图形化的监控, 也方便给领导出报告. 怎么说也是不错的. ...
- 发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下
发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下:https://segmentfault.com/a/1190000011377961 vantUI框架在vue项目中的应用 ...