此题看上去直接暴力dfs,你就可以拿到20pts
但是优化一下,设dp数组dp[pos][num]表示搜索到第pos位,总和为num时的余下位的权值进行一下记忆化搜索,就可以水到50pts
#include<bits/stdc++.h>
#define re register
#define int long long
#define inl inline
using namespace std;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return sum*f;
}
const int mod=998244353;
inl int count(int x){
int res=0;
while(x){
res++;
x-=(x&-x);
}
return res;
}
int n,m,k;
int v[110],a[1000],ans;
int dp[35][120010];
inl int dfs(int pos,int num){
if(pos==n+1) return count(num)<=k;
if(dp[pos][num]!=-1) return dp[pos][num];
int res=0;
for(re int i=0;i<=m;i++){
a[pos]=i;
res=(res+dfs(pos+1,num+(1<<i))*v[i]%mod)%mod;
}
return dp[pos][num]=res;
}
signed main(){
n=read(),m=read(),k=read();
memset(dp,-1,sizeof(dp));
for(re int i=0;i<=m;i++) v[i]=read();
printf("%lld",dfs(1,0));
return 0;
}
下面开始讲正解,其实是dp,设dp[i][j][p][q],表示前i位填了j个1,i+1位堆积了p个1,前i位共有q个1的答案
可以得到转移:dp[i][j][p][q]=dp[i-1][j-d][a][b]*(val[i]^d)*
d表示第i位填的1的个数,val[i]^d表示d个a[i]带来的贡献
表示a的组合情况
ab满足下列等式:
(a+d)/2=p
b+[(a+d)%2]=q
那么答案就为
Code
#include<bits/stdc++.h>
#define re register
#define int long long
#define inl inline
using namespace std;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return sum*f;
}
const int mod=998244353;
inl int count(int x){
int res=0;
while(x){
res++;
x-=(x&-x);
}
return res;
}
int n,m,k;
int v[110],a[1000],ans;
int dp[110][35][35][35];//放到i位,j个1,i+1堆了p个1,到i有q个合法1
inl int ksm(int a,int b){
int res=1;
while(b){
if(b&1) res=res*a%mod;
b>>=1;a=a*a%mod;
}
return res;
}
int c[35][35];
inl void init(){
for(re int i=0;i<=n;i++){
c[i][0]=1;
for(re int j=1;j<=i;j++){
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
return;
}
//int dp[35][120010];
/*inl int dfs(int pos,int num){
if(pos==n+1) return count(num)<=k;
if(dp[pos][num]!=-1) return dp[pos][num];
int res=0;
for(re int i=0;i<=m;i++){
a[pos]=i;
res=(res+dfs(pos+1,num+(1<<i))*v[i]%mod)%mod;
}
return dp[pos][num]=res;
}*/
signed main(){
n=read(),m=read(),k=read();
for(re int i=0;i<=m;i++) v[i]=read();
init();
for(re int i=0;i<=n;i++){
dp[0][i][i/2][i&1]=ksm(v[0],i)*c[n][i]%mod;
}
for(re int i=1;i<=m;i++){
for(re int j=0;j<=n;j++){
for(re int p=0;p<=j/2;p++){
for(re int q=0;q<=j;q++){
for(re int d=0;d<=j;d++){
int a=p*2-d;
int b=q-(a+d)%2;
if(a>=0&&b>=0){
dp[i][j][p][q]+=dp[i-1][j-d][a][b]*ksm(v[i],d)%mod*c[n-(j-d)][d]%mod;
}
dp[i][j][p][q]%=mod;
a++;
b=q-(a+d)%2;
if(a>=0&&b>=0){
dp[i][j][p][q]+=dp[i-1][j-d][a][b]*ksm(v[i],d)%mod*c[n-(j-d)][d]%mod;
}
dp[i][j][p][q]%=mod;
}
}
}
}
}
for(re int i=0;i<=n;i++){
for(re int j=0;j<=k-count(i);j++){
ans=(ans+dp[m][n][i][j])%mod;
}
}
printf("%lld\n",ans);
return 0;
}