【数论+组合数学】[省选十连测第十场]基本题
2017-07-15 17:23
260 查看
题目描述
【问题描述】所谓的考试,就一定会有一道基本题给大家送分,而不嵌套题目
的基本题怎么称得上基本呢?
我们可以把基本题具体看成由(),!四种字符组成的一个字符串,
一道基本题是由若干个嵌套题中间加上,分隔组成,而所谓的嵌套题
指 的 是 一 对 括 号 之 间 放 入 若 干 道 由 ! 分 隔 的 基 本 题 。 例 如
(()!(()!())),(()!())就是一道基本题。
当然在出题的时候我们会尽量避免出到重题,嵌套题 A 和 B 相同
指的是 A 中的所有基本题变换顺序之后可以变成 B,例如(()!(()))
与((())!())相同,而基本题 A 和 B 相同指的是将 A 的嵌套题平移后
可 以 变 成 B , 例 如 (),(()),(()!()) 与 (()),(()!()),() 还 有
(()!()),(),(())相同,与(()),(),(()!())不同。
这天小火车找到了 n 个合适的题目来出基本题,他想知道有多少
道恰有 n 对括号的合法且互不相同的基本题。例如当 n=3 时共有 5 个
不同的基本题,分别是“((()))”“(()!())”“((),())”“(()),()”
和“(),(),()”。
【输入格式】
第一行两个整数 t 和 p,其中 t 表示数据组数。保证 p 为质数。
接下来 t 行每行一个整数 n 表示一组询问。
【输出格式】
t 行每行一个整数表示答案,对 p 取模。
【样例输入】
5 2333
1
2
3
4
5
【样例输入】
1
2
5
14
42
分析
令qt[i]表示i个括号的嵌套题个数,jb[i]表示i个括号的基本题个数,f[i][j][k]表示嵌套题内部用i个括号及以下的基本题,k个嵌套题组成的j个括号的基本题(不考虑平移相同)的个数,t[i][j]表示从i个括号的基本题中选j个出来的方案数(一个元素可以被选多次),t[i][j]=C[jb[i]+j−1][j],可以用隔板法来验证,g[i][j]表示内部用i个括号及以下的基本题,j个括号组成的嵌套题个数。看一下转移
嵌套题的方案和内部基本题的顺序无关
g[i][j]=∑k=0⌊ji⌋g[i−1][j−k∗i]×t[i][k]qt[i]=g[i−1][i−1]
基本题的方案和顺序有关,先不考平移的是相同的
f[i][j][k]=∑l=0min(k,⌊ji⌋)f[i−1][j−l∗i][k−l]×C[k][l]×qt[i]k
如何计算jb[i]呢
然后我们考虑每一种情况在在f[i][i][j]中做出的贡献。
相当于一个有j个元素的多重集合的排列,通过循环移位能够变得相同的两个排列视为是相同的,我们要得到每一种不同的排列在f[i][i][j]中的贡献。
如果一个排列的循环节的长度是k,那它在f[i][i][j]中就会出现k次。
令now=f[i][i]
那我们需要怎么计算呢?
我们可以使每一种排列都出现j次。
循环节为k的排列会在now[k∗x]⋯x=1,2,3,4…出现,而且贡献都是k次,我们最终只需要使循环节为k的排列的贡献×jk即可。
我们换一种表示,令k为循环节的个数,我们就需要把循环节的个数为k的排列的贡献×k
循环节个数为k的排列在now[d]⋯d|k也有出现,所以我们要构造一个东西f(i),∑d|if(d)=d,狄利克雷卷积为f(i)=i的函数是什么呢?欧拉函数。
所以jb[i]=∑ij=1∑k|gcd(i,j)f[i][i/k][j/k]×ϕ(k)j
然后就能做啦。。。
代码
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; #define MAXN 250 int T,n,C[MAXN+10][MAXN+10],phi[MAXN+10],MOD,t[MAXN+10][MAXN+10],qt[MAXN+10],jb[MAXN+10],f[MAXN+10][MAXN+10],inv[MAXN+10]; void prepare(int n){ int i,j; for(i=0;i<=n;i++){ C[i][0]=1; for(j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD,phi[i]+=__gcd(i,j)==1; } inv[0]=inv[1]=1; for(i=2;i<=n;i++) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD; } void calqt(int n){ static int f[MAXN]={1}; int j,i,k; j=n-1; if(j) for(i=MAXN-1;i;i--) for(k=1;j*k<=i;k++) f[i]=(f[i]+1ll*f[i-j*k]*t[j][k])%MOD; qt =f[n-1]; } void caljb(int i,int n){ int j,k,l,now; for(j=n;j;j--) for(k=1,now=qt[i];i*k<=j;k++,now=(1ll*now*qt[i])%MOD) for(l=k;l<=j;l++) f[j][l]=(f[j][l]+1ll*f[j-k*i][l-k]*C[l][k]%MOD*now)%MOD; for(j=1;j<=i;j++){ int s=0; for(k=1;k<=j;k++) if(i%k==0&&j%k==0) s=(s+1ll*f[i/k][j/k]*phi[k])%MOD; jb[i]=(jb[i]+1ll*s*inv[j])%MOD; } } void solve(int n){ prepare(n); int i,j; f[0][0]=1; for(i=1;i<=n;i++){ calqt(i),caljb(i,n); t[i][0]=1; for(j=1;j<=n;j++) t[i][j]=1ll*t[i][j-1]*(jb[i]+j-1)%MOD*inv[j]%MOD; } } int main() { cin>>T>>MOD; solve(MAXN); while(T--){ cin>>n; cout<<jb <<endl; } }
相关文章推荐
- BZOJ 2142 礼物 组合数学+数论
- 暑假集训-组合数学及数论
- hdu 3944 DP? 组合数学与数论的结合
- HDU 1695 GCD (数论-整数和素数,欧拉函数,组合数学-容斥原理)
- 数论 - 组合数学 + 素数分解 --- hdu 2284 : Solve the puzzle, Save the world!
- 【数论】Irrelevant Elements, ACM/ICPC NEERC 2004, UVa1635 【组合数学】
- 2017.3.7 组合数学学习——四个基本计数原理、排列
- UVa 10290 {Sum+=i++} to Reach N (数论-整数和素数,组合数学-排列组合)
- HDU 3240 Counting Binary Trees [卡特兰数] 【数论+组合数学】
- 【数论】Choose and Divide, UVa10375 【组合数学】【唯一分解定理】【精度】
- HDU 1695 GCD (数论-整数和素数,组合数学-容斥原理)
- ACM中的基本数学知识掌握 --- 【数论/组合/博弈论/计算几何】非常重要
- HDU 1695 GCD (数论-整数和素数,组合数学-容斥原理)
- [codevs1262] 不要把球传我 数论+组合数学
- 数论 - 组合数学 + 素数分解 --- hdu 2284 : Solve the puzzle, Save the world!
- hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】
- poj2992数论与组合数学,略水。。。
- POJ 2154 Color(组合数学-波利亚计数,数论-欧拉函数,整数快速幂)
- Codeforces 396A 数论,组合数学
- hdu 4790 数论 实现 组合数学