题解:[NOIP2021] 数列

题目传送门

DP

状态设计

为了便于处理,称二进制最低位为第 \(0\) 位(权值为 \(2^0\))。

考虑从小到大填入 \(a_i\)

\(dp_{i,j,k,l}\) 表示处理了 \(a_1\sim a_i\)\(S\) 能进位到的最高位为 \(2^j\)(实际上最高位也可以不是 \(2^j\)之前\(a_i\) 最大值为 \(j-1\)),最高位 \(2^j\)\(k\) 个,已知 \(l\) 位为 \(1\) 的答案。

则答案为:

\[\sum_{\operatorname{count}(k)+l\leq K}dp_{n,m+1,k,l} \]

其中,\(\operatorname{count}(k)\) 表示 \(k\) 在二进制下 \(1\) 的个数。

状态转移

不好从其他状态转移到 \(dp_{i,j,k,l}\),那就考虑从 \(dp_{i,j,k,l}\) 向外转移。

假设再往 \(a\) 中填入 \(t\)\(j\),则有:

\[dp_{i+t,j+1,\left\lfloor\frac{k+t}{2}\right\rfloor,l+(k+t)\bmod 2}\leftarrow dp_{i+t,j+1,\left\lfloor\frac{k+t}{2}\right\rfloor,l+(k+t)\bmod 2}+dp_{i,j,k,l}\cdot v_j^t\cdot \binom{i+t}{t} \]

再往 \(a\) 中填入 \(t\)\(j\),则之后一共有 \(i+t\) 个;\(S\) 进位到了第 \(j+1\) 位;\(\left\lfloor\dfrac{k+t} {2}\right\rfloor\) 表示向下一位进的 \(1\) 的个数;\(l+(k+t)\bmod 2\) 是进位后剩下的没有进位的 \(1\) 与原来的 \(2^0\sim 2^{j-1}\)\(l\)\(1\) 的总共的数量。

然后再乘上一个组合数即可,从 \(i+t\) 个中选择 \(t\) 个填入。

边界条件

\[dp_{0,0,0,0}=1 \]

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<unordered_map>
using namespace std;
constexpr const int N=30,M=100,K=N,P=998244353;
int n,m,kk,v[M+1];
int dp[N+1][M+1+1][N+1][K+1];
int qpow(int a,int n){
	int base=a,ans=1;
	while(n){
		if(n&1){
			ans=1ll*ans*base%P;
		}
		base=1ll*base*base%P;
		n>>=1;
	}
	return ans;
}
int C(int n,int m){
	static int mem[N+M+1][N+1];
	if(n<m){
		return 0;
	}
	if(m==0||m==n){
		return 1;
	}
	if(mem[n][m]){
		return mem[n][m];
	}
	return mem[n][m]=(1ll*C(n-1,m)+C(n-1,m-1))%P;
}
int count(int x){
	int ans=0;
	while(x){
		if(x&1){
			ans++;
		}
		x>>=1;
	}
	return ans;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>m>>kk;
	for(int i=0;i<=m;i++){
		cin>>v[i];
	}
	dp[0][0][0][0]=1;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k<=n;k++){
				for(int l=0;l<=kk;l++){
					if(dp[i][j][k][l]){
						for(int t=0;i+t<=n;t++){
							int &pl=dp[i+t][j+1][k+t>>1][l+(k+t&1)];
							pl=(1ll*pl+1ll*dp[i][j][k][l]*qpow(v[j],t)%P*C(i+t,t)%P)%P;
						}
					}
				}
			}
		}
	}
	int ans=0;
	for(int k=0;k<=n;k++){
		for(int l=0;l<=kk;l++){
			if(count(k)+l<=kk){
				ans=(1ll*ans+dp[n][m+1][k][l])%P;
			}
		}
	}
	cout<<ans<<'\n';
	
	cout.flush();
	 
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
/*
8 9 4
934258593 150407625 187068439 162292791 219945760 512449588 803393963 983648121 484675481 412407699

642171527
*/
posted @ 2025-07-21 22:09  TH911  阅读(6)  评论(0)    收藏  举报