NOI.AC CSP-S 模拟 Round 2 T1 Count (组合数学) (容斥)

2024-01-30 01:32

本文主要是介绍NOI.AC CSP-S 模拟 Round 2 T1 Count (组合数学) (容斥),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门
题意:给定两个整数 n , m n, m n,m 求 k 元组 ( a 1 , a 2 , … , a k ) (a1,a2,…,ak) (a1,a2,,ak) 的个数,满足 a 1 , a 2 , … , a k a1,a2,…,ak a1,a2,,ak 为正整数
∑ a i = n \sum a_i=n ai=n a 1 , a 2 , … , a k a1,a2,…,ak a1,a2,,ak 均不是 m m m的倍数
n ≤ 1 e 18 , m ≤ 5 e 3 , k ≤ 2 e 3 n\le 1e18,m\le5e3,k\le2e3 n1e18,m5e3,k2e3


首先,如果没有 m m m 的限制,答案为 ( n − 1 k − 1 ) \binom{n-1}{k-1} (k1n1),插板,先全部减去1
考虑 m m m 的限制,发现不好容斥
发现最后的序列一定没有 m 的倍数,并且如果一个数 ≥ m \ge m m ,可以将它表示为 r + k m r+km r+km
于是我们可以将最后的序列抽象为先选好 a 1 , a 2 , . . . , a k a_1,a_2,...,a_k a1,a2,...,ak,并强制让 a i < m a_i<m ai<m,再对 a i a_i ai 随便加几个 m m m
枚举 ∑ r i = S \sum r_i = S ri=S r r r 为上文所述的 r r r,那么先选好的 a 1 , a 2 , . . . , a k a_1,a_2,...,a_k a1,a2,...,ak 的条件可以抽象为:

  1. ∑ a i = S \sum a_i = S ai=S
  2. a i ≤ m − 1 a_i \le m-1 aim1

然后在对几个 a i a_i ai 加上 m m m 的倍数,假设 ≤ n \le n n 的范围内有 c c c 个 m 的倍数
发现这个过程等价于把 c c c 分到 k 个集合,可以为空,方案数为 ( c + k − 1 k − 1 ) \binom{c+k-1}{k-1} (k1c+k1)
如何求第一个,一下令 m m m m − 1 m-1 m1,考虑容斥,强制 i i i > m >m >m
但如何求强制 i i i > m >m >m 的个数呢,发现这个问题等价于选 i 个位置出来 > m > m >m,然后将 n − i ∗ m n-i*m nim 分配给这 k k k 个集合,最后再将这 i i i 个加上 m m m,于是有
f ( n , m , k ) = ∑ i = 0 k ( − 1 ) i ( k i ) ( n − i ∗ m − 1 k − 1 ) f(n,m,k)=\sum_{i=0}^k(-1)^i\binom{k}{i}\binom{n-i*m-1}{k-1} f(n,m,k)=i=0k(1)i(ik)(k1nim1)

最后的答案
a n s = ∑ i = 0 k f ( i ∗ m + n % m , m − 1 , k ) ∗ ( n m − i + k − 1 k − 1 ) ans=\sum_{i=0}^k f(i*m+n\%m,m-1,k)*\binom{\frac{n}{m}-i+k-1}{k-1} ans=i=0kf(im+n%m,m1,k)(k1mni+k1)
n ≤ 1 e 18 n\le 1e18 n1e18,组合数暴力乘,有些不像 T 1 T1 T1


#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
ll read(){ll cnt = 0, f = 1; char ch = 0;while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();return cnt * f;
}
cs int N = 1e7 + 5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b);}
ll n; int m, k, fac[N], inv[N];
int C(ll n, int m){if(n < 0 || m < 0 || n < m) return 0;if(n < N) return mul(fac[n], mul(inv[m], inv[n - m]));else{int ret = inv[m];for(ll i = n; i >= n - m + 1; i--) ret = mul(ret, i % Mod);return ret;}
}
int g(ll n, int m){// devide n into m group and the group can be emptyif(n < 0) return 0;return C(n + m - 1, m - 1);
}
int f(int n, int m, int k){ // devide n into m group that the size of each group is less than k// can not be empty n -= m; if(n < 0) return 0;int ans = 0;for(int i = 0; i <= m; i++){int ret = mul(g(n - i * k, m), C(m, i));(i & 1) ? Add(ans, Mod - ret) : Add(ans, ret); } return ans;
}
int main(){n = read(), m = read(), k = read();fac[0] = fac[1] = inv[0] = inv[1] = 1;for(int i = 2; i < N; i++) fac[i] = mul(fac[i-1], i);for(int i = 2; i < N; i++) inv[i] = mul(Mod-Mod/i, inv[Mod%i]);for(int i = 2; i < N; i++) inv[i] = mul(inv[i], inv[i-1]);// 枚举 < m 的数的和  ll r = n % m; int ans = 0;for(int i = 0; i < k; i++){Add(ans, mul(f(i * m + r, k, m - 1), g((n - r) / m - i, k))); } cout << ans; return 0;
}

这篇关于NOI.AC CSP-S 模拟 Round 2 T1 Count (组合数学) (容斥)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658723

相关文章

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

uva 11044 Searching for Nessy(小学数学)

题意是给出一个n*m的格子,求出里面有多少个不重合的九宫格。 (rows / 3) * (columns / 3) K.o 代码: #include <stdio.h>int main(){int ncase;scanf("%d", &ncase);while (ncase--){int rows, columns;scanf("%d%d", &rows, &col

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯: