题解 [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;
}
posted @ 2022-06-02 22:00  Administrator-09  阅读(1)  评论(0编辑  收藏  举报