(2019Csp_s D2 T1)Emiya 家今天的饭

本题主要考查滚动数组

d p i , j , k dp_{i,j,k} dpi,j,k表示前 i i i种烹饪方法,假设最多的是食材 j j j,食材 j j j比其他食材多 k k k次出现

其中 i ∈ [ 1 , n ] , j ∈ [ 1 , m ] , k ∈ [ − n , n ] i \in [1,n],j \in [1,m],k \in [-n,n] i[1,n],j[1,m],k[n,n]

t h e n ⟹ d p i , j , k = d p i − 1 , j , k + ∑ l = 1 m ( l = j ? d p i − 1 , j , k − 1 : d p i − 1 , j , k + 1 ) then \Longrightarrow dp_{i,j,k}=dp_{i-1,j,k}+\sum_{l=1}^{m}(l=j?dp_{i-1,j,k-1} :dp_{i-1,j,k+1}) thendpi,j,k=dpi1,j,k+l=1m(l=j?dpi1,j,k1:dpi1,j,k+1)

总可能(不一定合法)为 ∏ i = 1 n ( 1 + ∑ j = 1 m a i , j ) \prod_{i=1}^{n}(1+\sum_{j=1}^{m}a_{i,j}) i=1n(1+j=1mai,j),

不合法的为 1 1 1(没有菜) + ∑ i = 1 m ∑ j = 1 n d p n , i , j +\sum_{i=1}^{m}\sum_{j=1}^{n}dp_{n,i,j} +i=1mj=1ndpn,i,j

当然,转移时可以用刷表法,把转移从 O ( m ) O(m) O(m) O ( 1 ) O(1) O(1)

还有,要开滚动数组(或者用int,只不过打着麻烦些)

#include
#include
using namespace std;
# define Type template
# define read read1()
Type inline T read1()
{
	T t=0;
	bool ty=0;
	char k;
	do k=getchar(),(k=='-')&&(ty=1);while('0'>k||k>'9');
	do t=(t<<3)+(t<<1)+(k^'0'),k=getchar();while('0'<=k&&k<='9');
	return ty?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define ll long long
# define mod 998244353ll
ll dp[2][2003][203];
int s,f[103][2003],m;
ll sum[103];
int main()
{
	//fre("meal");
	s=read,m=read;
	for(int i=0;i++^s;)
		for(int j=0;j++^m;sum[i]%=mod)
			sum[i]+=f[i][j]=read;
	ll ans=1;
	for(int i=0;i++^s;)
		ans=ans*(sum[i]+1)%mod;
	for(int i=0;i++^m;)
		dp[0][i][100]=1;
	for(int i=0;i^s;++i)
		for(int j=0;j++^m;)
			for(int k=-100;k<=100;++k)
				if(dp[i&1][j][k+100])
				{
					(dp[~i&1][j][k+100]+=dp[i&1][j][k+100])%=mod;
					(dp[~i&1][j][k+99]+=dp[i&1][j][k+100]*(sum[i+1]-f[i+1][j]))%=mod;
					(dp[~i&1][j][k+101]+=dp[i&1][j][k+100]*f[i+1][j])%=mod;
					dp[i&1][j][k+100]=0;
				}
	for(int j=0;j++^m;)
		for(int k=101;k<=200;++k)
			if(dp[s&1][j][k])
				ans=(ans-dp[s&1][j][k])%mod;
	printf("%lld",(ans-1+mod)%mod);
	return 0;
}

你可能感兴趣的:(c++)