[hdu7011]被EI加0了
作者:互联网
注意到仅关心于权值大小,预处理出$F_{i}(n)$表示$a_{1},a_{2},...,a_{n}$中恰填$i$种不同的数的方案数,那么显然答案即为$\sum_{i=1}^{\min(n,m)}{m\choose i}F_{i}(n)$,可以$o(n)$计算
下面,问题即如何求出$F_{i}(n)$——
考虑从小到大填数,注意到并没有确定$n$,因此填数是在原序列中插入数
不难发现,如果$x$填了不少于两次且在末尾填了,那么令$i$为其第一次填的位置,则$\max_{k=1}^{i}a_{k}=a_{n}=x$且显然$i<n$,同时只需要之后在$a_{i}$之前填一个数就可以避免此情况
考虑容斥,即将序列中满足$\exists i<j\le n$且$\max_{k=1}^{i}a_{k}=\min_{k=j}^{n}a_{k}$的$a_{i}$前缀最大值取出(即不存在更小的满足条件的$i'$使得$a_{i'}\ge a_{i}$),并对序列容斥(任选其中的子序列,若子序列长度为$l$,则贡献系数为$(-1)^{l}$)
注意到对于这样的前缀最大值,其之前不能再填数字(从小到大填数),即可以用dp计算
具体的,令$g_{i}(a,b)$填了$i$种数且当前容斥选择的序列末尾为$a$(若$a=0$即序列为空)且填了$a+b$个数的方案数(带贡献系数),不难得到转移为
$$
\begin{cases} { b+s\choose s}g_{i}(a,b)\rightarrow g_{i+1}(a,b+s)&(s\ge 1)\\-{b-k+s\choose s}g_{i}(a,b)\rightarrow g_{i+1}(a+k+1,b-k+s+1) &(0\le k\le b,s\ge 0)\end{cases}
$$
进一步的,有$F_{i}(n)=\sum_{a=0}^{n}g_{i}(a,n-a)$,但直接根据递推式计算$g$的复杂度为$o(n^{5})$,无法通过
下面,问题即如何快速求出$g_{i}(a,b)$——
考虑$g$的二元生成函数$f_{i}(x,y)=\sum_{a,b\ge 0}g_{i}(a,b)x^{a}\frac{y^{b}}{b!}$(其中$y$上是指数生成函数),代入转移即
$$
f_{i+1}(x,y)=(e^{y}-1)f_{i}(x,y)-\sum_{a,b\ge 0}g_{i}(a,b)\sum_{k=0}^{b}\sum_{s\ge 0}{b-k+s\choose s}x^{a+k+1}\frac{y^{b-k+s+1}}{(b-k+s+1)!}
$$
前者显然容易处理,下面先考虑后者(去掉负号):
事实上,$f_{i}(x,y)$总可以被写作$\sum_{p,q\ge 0}c_{p,q}x^{p}e^{qy}$的形式(正确性归纳即可),显然其对相同的$a,b$有相同的系数(但对$p,q$没有),不妨仅考虑其中一项$x^{p}e^{qy}$的影响,(将$e^{qy}$泰勒展开后)代入即
$$
\sum_{b\ge 0}q^{b}\sum_{k=0}^{b}\sum_{s\ge 0}{b-k+s\choose s}x^{p+k+1}\frac{y^{b-k+s+1}}{(b-k+s+1)!}
$$
调换枚举变量,依次枚举$k,b-k+s$和$b-k$,即为
$$
\sum_{k\ge 0}q^{k}x^{p+k+1}\sum_{s'\ge 0}\frac{y^{s'+1}}{(s'+1)!}\sum_{b'=0}^{s'}q^{b'}{s'\choose b'}
$$
利用公式,不难得到即为$\frac{x^{p+1}}{1-qx}\frac{1}{q+1}(e^{(q+1)y}-1)$
(前者由于式子与$a,b$无关,因此对相同的$p,q$也有相同的系数,直接代入即可)
综上,两者都可以$o(n^{2})$计算,也即可$o(n^{3})$求出所有$f_{i}(x,y)$,进而有
$$
F_{i}(n)=\sum_{a=0}^{n}g_{i}(a,n-a)=\sum_{a=0}^{n}\sum_{q\ge 0}c_{a,q}q^{n-a}
$$
预处理出$S_{q,n}=\sum_{a=0}^{n}q^{n-a}c_{a,q}=qS_{q,n-1}+c_{n,q}$,那么即$F_{i}(n)=\sum_{q\ge 0}S_{q,n}$,也可以$o(n^{3})$求出
(这个方法也可以用于$\frac{1}{1-qx}$的计算上)
另外,由于内存限制,需要对$f$滚动计算
最终,总复杂度为$o(n^{3}+Tn)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 305 4 #define mod 998244353 5 #define ll long long 6 int t,n,m,ans,inv[N],f[2][N][N],F[N][N]; 7 int main(){ 8 n=300; 9 inv[0]=inv[1]=f[0][0][0]=1; 10 for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 11 for(int i=1;i<=n;i++){ 12 int ii=(i&1); 13 memset(f[ii],0,sizeof(f[ii])); 14 for(int p=0;p<=n;p++) 15 for(int q=0;q<i;q++){ 16 f[ii][p][q+1]=(f[ii][p][q+1]+f[ii^1][p][q])%mod; 17 f[ii][p][q]=(f[ii][p][q]-f[ii^1][p][q]+mod)%mod; 18 } 19 for(int q=0;q<i;q++){ 20 int s=0; 21 for(int j=0;j<n;j++){ 22 s=((ll)s*q+f[ii^1][j][q])%mod; 23 f[ii][j+1][q+1]=(f[ii][j+1][q+1]-(ll)s*inv[q+1]%mod+mod)%mod; 24 f[ii][j+1][0]=(f[ii][j+1][0]+(ll)s*inv[q+1])%mod; 25 } 26 } 27 for(int q=0;q<=i;q++){ 28 int s=f[ii][0][q]; 29 for(int j=1;j<=n;j++){ 30 s=((ll)s*q+f[ii][j][q])%mod; 31 F[i][j]=(F[i][j]+s)%mod; 32 } 33 } 34 } 35 scanf("%d",&t); 36 while (t--){ 37 scanf("%d%d",&n,&m); 38 ans=0; 39 int s=1; 40 for(int i=1;i<=min(n,m);i++){ 41 s=(ll)s*(m-i+1)%mod*inv[i]%mod; 42 ans=(ans+(ll)s*F[i][n])%mod; 43 } 44 printf("%d\n",ans); 45 } 46 return 0; 47 }View Code
标签:frac,qy,hdu7011,sum,ge,choose,EI,define 来源: https://www.cnblogs.com/PYWBKTDA/p/15142639.html