开始看到这道题心中一紧
这怕不是道容斥
于是极其痛苦的想了想
最后还是不会
但是大佬一眼看出这是一道类似区间dp的dp题
完全四次方暴力加上各种优化就过了
dp[i][j]表示在长为i的区间里贡献为j的方案数
我们考虑从小到大放入这些数
枚举区间长度以及放入数的位置
对于每一个插入的数来说
扫描二维码关注公众号,回复:
3804588 查看本文章
左右两边块内的贡献并不会改变
只有当前这个点会有min(k+1,n-k)的贡献
这样一直放到最后
dp[n][x]就是答案了
QAQ贴一下代码
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,x,dp[81][505],jiecheng[550],inv[505],LOG[505],c[510][510],maxa;
int cc(int x,int y)
{
if(y>x) return 0;
return 1ll*jiecheng[x]*inv[y]%mod*inv[x-y]%mod;
}
int minn(int x,int y)
{
if(x<y)
return x;
return y;
}
int moc(int x)
{
if(x>mod)
x-=mod;
return x;
}
int main()
{
freopen("good.in","r",stdin);
freopen("good.out","w",stdout);
jiecheng[1]=jiecheng[0]=1;
for(int i=2;i<=100;i++)
{
jiecheng[i]=1ll*jiecheng[i-1]*i%mod;
}
inv[1]=inv[0]=1;
for(int i=2;i<=100;i++)
{
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
for(int i=2;i<=100;i++)
{
inv[i]=1ll*inv[i]*inv[i-1]%mod;
}
for(int i=0;i<=505;i++)
{
for(int j=0;j<=505;j++)
c[i][j]=cc(i,j);
}
cin>>n>>x;
dp[0][0]=1;
for(int i=2;i<=n;i++)
LOG[i]=LOG[i>>1]+1;
maxa=3;
for(register int i=1;i<=n;i++)
{
for(register int j=minn(x,minn(LOG[i]*i,300));j>=0;j--)
{
for(register int k=0;k<=i-1;k++)
{
for(register int l=j;l>=0;l--)
{
int now=j+minn(k+1,i-k);
dp[i][now]=moc(dp[i][now]+1ll*dp[k][l]*dp[i-k-1][j-l]%mod*c[i-1][k]%mod);
}
}
}
}
cout<<dp[n][x];
return 0;
}