题解 [AGC012F] Prefix Median
被这题折腾了一个晚上.jpg
邓老师名言:你先想想怎么判合法
那么考虑一个合法的 \(p\) 的条件是什么
首先 \(p_i\) 是中位数,那么将 \(a\) 升序排序后有 \(p_i\in[a_i, a_{2n-i}]\)
然后发现 \(p_i\) 一定是 \(p_{i-1}\) 或其前驱后继
所以要求不存在 \(j<i\),\(p_i<p_j<b_{i+1}\) 或 \(p_{i+1}<b_j<b_i\)
可以归纳证明这个是充分条件
然后发现每个满足上述条件的 \(p\) 都可以构造一组合法的 \(a\),所以也是必要的
然后考虑怎么对这个东西计数
反正我感觉很神仙而且题解没看懂
考虑 \(p_n=a_n\),于是尝试倒序处理
因为只是对合法的 \(p\) 做计数,此时没有了 \(a\) 的限制
考虑维护出 \(p_i\) 可选的取值集合
那么发现若 \(a_i\neq a_{i+1}\) 则可以加入 \(a_i\),\(a_{2n-i}\) 同理
然后若 \(p_i\neq p_{i+1}\),那么 \(p_{i+1}\) 仍然可以选(因为限制 2 是小于号)
但是 \((p_i, p_{i+1})\) 中的数就不能选了(啊这两个不一定谁大谁小,意会一下)
于是令 \(f_{i, j, k}\) 为考虑到位置 \(i\),在 \(n\) 左边还有 \(j\) 个位置可以选,右边有 \(k\) 个位置可以选的方案数
转移下来是 \(O(n^4)\) 的
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 110
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll ans;
const ll mod=1e9+7;
int a[N], f[N][N][N];
signed main()
{
n=read(); m=n<<1;
for (int i=1; i<m; ++i) a[i]=read();
sort(a+1, a+m);
f[n][0][0]=1;
for (int i=n-1; i; --i) {
int tl=a[i]!=a[i+1], tr=a[m-i]!=a[m-i-1];
for (int l=0; l<m; ++l) {
for (int r=0; r<m; ++r) {
f[i][l+tl][r+tr]=(f[i][l+tl][r+tr]+f[i+1][l][r])%mod;
for (int j=0; j<l+tl; ++j)
f[i][j][r+tr+1]=(f[i][j][r+tr+1]+f[i+1][l][r])%mod;
for (int j=0; j<r+tr; ++j)
f[i][l+tl+1][j]=(f[i][l+tl+1][j]+f[i+1][l][r])%mod;
}
}
}
for (int i=0; i<m; ++i)
for (int j=0; j<m; ++j)
ans=(ans+f[1][i][j])%mod;
printf("%lld\n", ans);
return 0;
}