您的位置:首页 > 其它

【数论+组合数学】[省选十连测第十场]基本题

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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: