给定两个序列 A 和 B,按照 A_i 的增序对它们进行排序(如果 A_i 相等,则按照 B_i 来确定顺序)。对于集合 {1, 2, ..., N} 的每个非空子集 S,满足 max_{i∈S} A_i = A_{max(S)}。因此,我们可以将问题转化如下。
定义 f(i, j) 为从 B_1, B_2, ..., B_i 中选择零个或多个元素,使它们的和等于 j。求下面的值:
∑ {i=1} ^ {N} ∑ {j=0} ^ {A_i - B_i} f(i-1, j)
显然,对于 f(i, j),我们只需考虑 i 在 0 到 N(包括两端)之间的取值范围,以及 j 在 0 到 max(A)(包括两端)之间的取值范围。因此,我们可以适当使用动态规划(DP)来计算 f(i, j) 的值,从而在总共 O(Nmax(A)) 的时间复杂度内解决问题。
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353, maxi = 5000;
int main(){
int N; cin >> N;
vector<pair<int,int>> data(N);
for(int i=0; i<N; i++) cin >> data[i].first;
for(int i=0; i<N; i++) cin >> data[i].second;
sort(data.begin(),data.end());
vector<int> A(N),B(N);
for(int i=0; i<N; i++) tie(A[i],B[i]) = data[i];
vector<vector<int>> dp(N+1,vector<int>(maxi+1));
dp[0][0] = 1;
int ans = 0;
for(int i=0; i<N; i++){
for(int j=0; j<=maxi; j++){
dp[i+1][j] = dp[i][j];
if(B[i] <= j){
dp[i+1][j] += dp[i][j-B[i]];
dp[i+1][j] %= mod;
}
if(j <= A[i]-B[i]){
ans += dp[i][j];
ans %= mod;
}
}
}
cout << ans << endl;
}