机房dp专房训练赛

开始看到这道题心中一紧

这怕不是道容斥

于是极其痛苦的想了想

最后还是不会

但是大佬一眼看出这是一道类似区间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;
}

猜你喜欢

转载自blog.csdn.net/ENESAMA/article/details/82260458