ABC 313
省流:ABC 没有什么好讲的,DEG 比较简单。
D
先求出 \(1\) 和其他数的异或值,再计算。
第一种是 \(2\sim n-k+1\) 的,第二种是 \(n-k+2\sim n\) 的。
E
连续两个 \(>1\) 不会结束,其他的情况从后往前处理即可。
计算每一个 \(>1\) 的贡献是几个 \(1\)。
F
-
如果出现 \(X_i=Y_i\),必须翻,如果 \(B_i>A_i\),先翻过来再说,不会更劣。后面只考虑 \(X_i\neq Y_i\)。
-
如果对于一个 \(a\),有 \(X_i=a\) 或 \(Y_i=a\),\(a\) 翻转的概率是 \(\frac{1}{2}\),否则为 \(0\)。(可以用二项式定理证明)
-
抽象成图,\(X_i\) 到 \(Y_i\) 连一条边。
-
每个点权是 \(\frac{A_i+B_i}{2}-A_i\),是选择它的“贡献”。
-
显然,连接两个点权是正的边,直接连接;连接两个点权是负的边,不可能连接。处理完,去掉这些边。
-
图变成了二分图。\(40\div 2=20\),\(2^{20}\) 很合理。
-
若负的点数量 \(\le 20\),可以直接枚举,与它们连的正的边一定会选,\(O(2^20\times 20^2)\),预处理可以 \(O(2^{20}\times 20)\)。(最坏)
-
反之,在正的上面 dp,\(dp_{i,msk}\) 代表负的中选到了 \(i\),正的选了 \(msk\)。\(O(2^{20}\times 20)\)。
G
操作 \(A\) 都在 \(B\) 前面,这样答案不会重复(\(A\) 在 \(B\) 后面相当于没做)。把问题转化成求 floor sum,类欧板子套上去即可。
Ex
-
给 \(A\) 和 \(B\) 排序没有影响。
-
定义 \(C\),\(C_i=\min(A_i,A_{i-1}),C_1=A_1,C_{N+1}=A_N\)。
-
\(B_i>C_i\) 即可。
考虑插入 dp。\(dp_{i,j}(i\ge j)\) 表示前 \(i\) 个 \(A\) 分成 \(j\) 段(此时 \(B\) 到了 \(i+j\))。段数从 \(a\) 变到 \(b\) 时,\(B_{a},B_{a+1},\cdots,B_{b}\) 均要大于 \(A_{i+1}\)。
转移 \(3\) 种情况:
-
\(A_{i}\) 单独成段。
-
\(A_{i}\) 在一段左或右边。
-
\(A_{i}\) 连接两段。
代码很好写。
code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 5e3+3;
const ll mod = 998244353;
int n;
int a[N],b[N];
ll dp[N][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for (int i=0; i<n; i++){
cin>>a[i];
}
for (int i=0; i<n+1; i++){
cin>>b[i];
}
sort(a,a+n);
sort(b,b+1+n);
dp[0][0]=1;
for (int i=0; i<n; i++){
for (int bl=0; bl<=i; bl++){
for (int ty=0; ty<3; ty++){
if (i+bl+1-ty>n || ty>bl){
continue;
}
if (ty!=2 && b[i+bl]<a[i]){
continue;
}
if (ty==0){
(dp[i+1][bl+1]+=dp[i][bl]*1ll*(bl+1)%mod)%=mod;
}
if (ty==1){
(dp[i+1][bl]+=dp[i][bl]*1ll*(2ll*bl)%mod)%=mod;
}
if (bl-1>=0 && ty==2){
(dp[i+1][bl-1]+=dp[i][bl]*1ll*(bl-1)%mod)%=mod;
}
}
}
}
cout<<dp[n][1]<<endl;
return 0;
}
// don't waste time!!!