Problem Author: | wuhudsm |
Prepared by: | wuhudsm |
Editorial: | wuhudsm |
Let dp[i][j][v] represent the number of ways to arrange the first numbers into segments with a mex value of . We have:
Here, f(x, v) is the number of different ways to arrange an array of length with a mex value of . To compute f(x, v), we can use the inclusion-exclusion principle:
An important observation is that the length of a subsegment with a mex value of should be at least . So only the state where v \times j \leq n is legal. In other words, we only need to compute O(n^2 \log n) dp[i][j][v] states. The total complexity is O(n^3 \log n).
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <bitset>
#include <unordered_map>
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int N=1000010;
const int M=401;
const int LOGN=28;
const ll TMD=998244353;
const ll INF=2147483647;
int T;
ll n,m,R;
ll f[M][M];
ll dp[M][M][M];
/*
* stuff you should look for
* [Before Submission]
* array bounds, initialization, int overflow, special cases (like n=1), typo
* [Still WA]
* check typo carefully
* casework mistake
* special bug
* stress test
*/
//-------------------------------------------------
//涉及变量:fac[],inv[],TMD,N(上界)
//注意:TMD自取
ll fac[N],inv[N];
ll pw(ll x,ll p)
{
if(!p) return 1;
ll y=pw(x,p>>1);
y=(y*y)%TMD;
if(p&1) y=(y*(x%TMD))%TMD; //典中典:若底数太大要对底数取模!
return y;
}
void init_C()
{
fac[0]=1;
for(int i=1;i<N;i++) fac[i]=(fac[i-1]*i)%TMD;
inv[N-1]=pw(fac[N-1],TMD-2);
for(int i=N-2;i>=0;i--) inv[i]=(inv[i+1]*(i+1))%TMD;
}
ll C(int n,int m)
{
if(n<m||n<0||m<0) return 0; //特殊情况
return fac[n]*inv[m]%TMD*inv[n-m]%TMD;
}
ll A(int n,int m)
{
if(n<m||n<0||m<0) return 0; //特殊情况
return fac[n]*inv[n-m]%TMD;
}
ll INV(ll x)
{
return pw(x,TMD-2);
}
//-------------------------------------------------
void init_f()
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
if(j>m+1) continue;
for(int k=0;k<=j;k++)
{
ll sig=((k&1)?-1:1);
if(j<=m) f[i][j]=(f[i][j]+sig*C(j,k)*pw(m-k,i)%TMD+TMD)%TMD;
else f[i][j]=(f[i][j]+sig*C(j,k)*pw(m+1-k,i)%TMD+TMD)%TMD;
//
//if(i==2&&j==2) printf("k=%d f[2][2]=%I64d",k,f[2][2]);
//
}
}
}
}
void init()
{
cin>>n>>m>>R;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
f[i][j]=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
dp[i][j][k]=0;
init_f();
}
void solve()
{
//dp[1][1][0]=m-1;
//dp[1][1][1]=1;
//
//printf("f[2][0]=%I64d f[2][1]=%I64d f[2][2]=%I64d\n",f[2][0],f[2][1],f[2][2]);
//
for(int i=0;i<=n;i++) dp[0][0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
for(int k=0;k*j<=i;k++)
{
for(int l=1;l<=i;l++)
{
dp[i][j][k]=(dp[i][j][k]+dp[i-l][j-1][k]*f[l][k])%TMD;
}
}
}
}
for(int i=1;i<=R;i++)
{
ll ans=0;
for(int k=0;k<=n;k++)
ans=(ans+dp[n][i][k])%TMD;
cout<<ans<<(i==R?'\n':' ');
}
}
//-------------------------------------------------------
void gen_data()
{
srand(time(NULL));
}
int bruteforce()
{
return 0;
}
//-------------------------------------------------------
int main()
{
fastio;
init_C();
cin>>T;
while(T--)
{
init();
solve();
/*
//Stress Test
gen_data();
auto ans1=solve(),ans2=bruteforce();
if(ans1==ans2) printf("OK!\n");
else
{
//Output Data
}
*/
}
return 0;
}