给定两个序列 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;
}