CF1946E Girl Permutation

LawrenceD發表於2024-08-18

中文題面:https://www.luogu.com.cn/problem/CF1946E

先考慮只要求字首最大值怎麼做。從前往後很容易想到\(O(n^3)\)的dp,用字首和最佳化可以到\(O(n^2)\).注意相對順序,\([p_i,p_{i+1}-1]\)選擇的數,必須讓最大的放在最前面才合法。比如選1,3,9,在[5,8]這個區間,只有9,1,3和9,3,1是合法的。從後往前考慮每一段,發現前面的選擇對後面沒有影響(相對順序不變)。

字尾最大值考慮的方法類似。注意判斷合法狀態。a[m1] != b[1] || a[1] != 1 || b[m2] != n, 即最大值在前字尾相同,字首第一個在1,字尾最後一個在n。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 1e9 + 7;
const int N = 2e5 + 11;
int a[N], b[N];
int n, m1, m2;
LL fac[N], invo[N], inv[N];
LL C(int n, int m){
  return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
void work(){
  cin>>n>>m1>>m2;
  for(int i = 1;i <= m1; i++){
    scanf("%d", &a[i]);
  }
  for(int i = 1;i <= m2; i++){
    scanf("%d", &b[i]);
  }
  if(a[m1] != b[1] || a[1] != 1 || b[m2] != n){
    cout<<0<<endl;
    return ;
  }
  LL res = C(n - 1, a[m1] - 1);
  LL tmp = a[m1] - 1;
  for(int i = m1 - 1;i >= 1; i--){
    tmp--;
    res = res * C(tmp, a[i+1] - a[i] - 1) % mod * fac[a[i+1]-a[i]-1] % mod;
    tmp -= a[i+1] - a[i] - 1;
  }
  tmp = n - a[m1];
  for(int i = 1;i < m2; i++){
    tmp--;
    res = res * C(tmp, b[i+1] - b[i] - 1) % mod * fac[b[i+1]-b[i]-1] % mod;
    tmp -= b[i+1] - b[i] - 1;
  }
  cout<<res<<endl;
}
int main(){
  int T;
  cin>>T;
  fac[0] = fac[1] = inv[0] = inv[1] = 1;
  for(int i = 1;i <= 2e5; i++){
    fac[i] = 1ll * fac[i-1] * i % mod;
  }
  for(int i = 2;i <= 2e5; i++){
    inv[i] = (mod - mod / i) * inv[mod%i] % mod;
  }
  for(int i = 2;i <= 2e5; i++){
    invo[i] = inv[i];
    inv[i] = inv[i-1] * inv[i] % mod;
  }
  while(T--)work();
  return 0;
}

相關文章