Official

F - Two Exams Editorial by en_translator


First of all, let’s reduce the information into the form of “the person who was in the \(i\)-th place in the first test was in the \(A_i\)-th place in the second test.” For example, for Sample Input 1, we have \(A=(3,2,4,1)\).

Consider determining if each citizen should be chosen or not in the order of the rank for the first test, highest to the lowest.
Since we are determining them in the increasing order of the rank for the first test, we can say that “when determining whether or not to choose Citizen \(X\), if there is Citizen \(Y\) prior to citizen \(X\) who was not chosen, then \(X\) should be in the higher rank than \(Y\) in the second test.”

Based on this property, consider the DP (Dynamic Programming) in the following form.
\(dp[\) the first \(i\) citizens have been inspected \(][\) the number of people already chosen \(][\) the smallest rank of citizens not chosen so far (or \(\infty\) if there is no such citizen) \(]\) = (The number of ways to choose out of the first \(i\) people)

The transition occurs from each \(dp[i][j][k]\) to the case where Citizen \(i+1\) is chose or not. (Note that in some cases we are not allowed to choose.) For more details, please refer to the Sample code. (It is a good exercise of finding out the transitions from the form of DP, so we recommend you to consider it by yourself.)
Note that we only have to store the DP table with the largest first index, since we only have to use \(dp[i]\) when computing \(dp[i+1]\).
The complexity of this DP is \(O(N^3)\).

Sample code (C++):

#include<bits/stdc++.h>
#define mod 998244353

using namespace std;

int main(){
  int n,k;
  cin >> n >> k;
  vector<int> p(n),q(n);
  for(auto &nx : p){cin >> nx;}
  for(auto &nx : q){cin >> nx;}
  vector<int> v(n);
  for(int i=0;i<n;i++){v[p[i]-1]=q[i]-1;}
  vector<vector<int>> dp(k+1,vector<int>(n+1,0));
  dp[0][n]=1;
  for(int i=0;i<n;i++){
    vector<vector<int>> ndp(k+1,vector<int>(n+1,0));
    for(int x=0;x<=k;x++){
      for(int y=0;y<=n;y++){
        if(x<k && v[i]<y){
          ndp[x+1][y]+=dp[x][y];
          ndp[x+1][y]%=mod;
        }
        ndp[x][min(y,v[i])]+=dp[x][y];
        ndp[x][min(y,v[i])]%=mod;
      }
    }
    dp.swap(ndp);
  }
  int res=0;
  for(auto &nx : dp[k]){res+=nx;res%=mod;}
  cout << res << '\n';
  return 0;
}

posted:
last update: