[luogu4484]最长上升子序列

标算是状压dp+打表,前者时间复杂度为$o(n^{2}2^{n})$,并通过打表做到$o(1)$

参考loj2265中关于杨表的相关知识,不难发现答案即$\frac{\sum_{a\vdash n}a_{1}f_{a}^{2}}{n!}$

记$P(n)$为$a\vdash n$的方案数,后者$f_{a}$可以$o(n)$计算,总复杂度即$o(nP(n))$

不难发现$P(n)$即为A000041,有$P(28)=3718$(甚至$P(60)\le 10^{6}$),显然可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 30
 4 #define mod 998244353
 5 #define ll long long
 6 vector<int>v;
 7 int n,ans,inv[N];
 8 void calc(int k,int lst){
 9     if (!k){
10         int s=1;
11         for(int i=0;i<v.size();i++)
12             for(int j=1;j<=v[i];j++){
13                 int tot=v[i]-j;
14                 for(int k=i;k<v.size();k++)
15                     if (j<=v[k])tot++;
16                 s=(ll)s*inv[tot]%mod;
17             }
18         for(int i=1;i<=n;i++)s=(ll)s*i%mod;
19         s=(ll)v[0]*s%mod*s%mod;
20         ans=(ans+s)%mod;
21         return;
22     }
23     for(int i=min(k,lst);i;i--){
24         v.push_back(i);
25         calc(k-i,i);
26         v.pop_back();
27     }
28 }
29 int main(){
30     inv[0]=inv[1]=1;
31     for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
32     scanf("%d",&n);
33     calc(n,n);
34     for(int i=1;i<=n;i++)ans=(ll)ans*inv[i]%mod;
35     printf("%d\n",ans);
36     return 0;
37 } 
View Code

 

posted @ 2021-09-02 19:44  PYWBKTDA  阅读(41)  评论(0编辑  收藏  举报