思路:转换题目为m+1个位置,每个位置可以放一个非负整数,并且非负整数和为n,每个位置满2进1。
假如前四个位置一次为a,b,c
权值就是V1aV2bV3c
方案数为CnaCn−abCn−a−bc;
所以开一个四维数组f[i][j][k][l]
i表示放第i个位置,j表示放完后和为j,k表示进k,l表示已经有l个1;
f[i+1][o][(k+o-j)/2][(k+o-j)%2+l]=f[i+1][o][(k+o-j)/2][(k+o-j)%2+l]+f[i][j][k][l]*kuai[i+1][o-j]*zhu[n-j][o-j]
意思就是在第i+1个位置放o−j,kuai[i][j]是Vij,zhu[i][j]是Cij;
然后因为对于f[m+1][n][i][j]的话,因为没有完全进位,所以把i转换为二进制数判断1的个数p,如果j+p<=k则合法,计入答案。
//mei you zhong wen shu ru fa zhi neng da pin yin le
//hua you chong kai zhi ri
//ren wu zai shao zhi nian
#include<bits/stdc++.h>
using namespace std;
#define int long long
int read( )
{
char ch;
ch=getchar( );
int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0')
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int n,m,k,v[101];
int f[111][35][35][35];
const int mod=998244353;
int kuai[34][35];
int zhu[35][35];
int ans,kk;
signed main( )
{
n=read( );
m=read( );
kk=read( );
for(int i=1;i<=m+1;i++)v[i]=read( );
for(int i=1;i<=m+1;i++)
{
kuai[i][0]=1;
for(int j=1;j<=n;j++)kuai[i][j]=kuai[i][j-1]*v[i]%mod;
}
zhu[0][0]=1;
for(int i=1;i<=33;i++)
{
zhu[i][0]=1;
for(int j=1;j<=i;j++)zhu[i][j]=(zhu[i-1][j]+zhu[i-1][j-1])%mod;
}
for(int i=0;i<=n;i++)
{
f[1][i][i/2][i%2]=kuai[1][i]*zhu[n][i]%mod;
}
for(int i=1;i<=m;i++)
{
for(int j=0;j<=n;j++)
{
int y=min(i,j);
for(int k=0;k<=j/2;k++)
{
for(int l=0;l<=y;l++)
{
if(f[i][j][k][l]==0)continue;
for(int o=j;o<=n;o++)
{
int kk=o-j+k;
f[i+1][o][kk/2][l+kk%2]+=f[i][j][k][l]*kuai[i+1][o-j]%mod*zhu[n-j][o-j]%mod;
f[i+1][o][kk/2][l+kk%2]=f[i+1][o][kk/2][l+kk%2]%mod;
}
}
}
}
}
for(int k=0;k<=n/2;k++)
{
for(int l=0;l<=min(n,m+1);l++)
{
int p=0;
int u=k;
while(u>0)
{
if(u%2==1)p++;
u=u/2;
}
if(l+p<=kk)ans=(ans+f[m+1][n][k][l])%mod;
}
}
cout<<ans;
}