Atcoder AGC012F : Prefix Median

传送门

题解:
先把 a a a排序, b b b 序列能被构造出来,则:

  1. a i ≤ b i ≤ a 2 n − i a_i \le b_i \le a_{2n-i} aibia2ni
  2. 不存在 i , j i,j i,j i < j , b j < b i < b j + 1 i \lt j,b_j \lt b_i \lt b_{j+1} i<j,bj<bi<bj+1,或者 b j + 1 < b i < b j b_{j+1} \lt b_i \lt b_j bj+1<bi<bj。这个应该很好理解,因为中位数每次最多挪动1。 我们也很好构造出 a a a来对应 b b b

观察到 b b b越靠后限制越强,我们从后往前DP,维护 f i , j , k f_{i,j,k} fi,j,k表示第 i i i个,可选数小等于 b i + 1 b_{i+1} bi+1的有 j j j个,大于 b i + 1 b_{i+1} bi+1的有 k k k个。 然后枚举下一个填什么即可。 时间复杂度 O ( n 4 ) O(n^4) O(n4)

#include 
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=105, mod=1e9+7;
inline void add(int &x,int y) {x=(x+y>=mod) ? (x+y-mod) : (x+y);}

int n,a[N];
int f[N/2][N][N];

int main() {
	n=rd();
	for(int i=1;i<=2*n-1;i++) a[i]=rd();
	sort(a+1,a+2*n);
	
	f[n][1][0]=1;
	for(int i=n-1;i>=1;i--) {
		int al=(a[i]!=a[i+1]), ar=(a[2*n-i]!=a[2*n-i-1]);
		for(int l=0;l<=2*n-1;++l)
			for(int r=0;r+l<=2*n-1;++r) if(f[i+1][l][r]) {
				int &t=f[i+1][l][r];	
				for(int dl=1;dl<=l+al;++dl) add(f[i][l+al-dl+1][r+ar+(dl>1)],t);
				for(int dr=1;dr<=r+ar;++dr) add(f[i][l+al+1][r+ar-dr],t);
			}
	}
	
	int ans=0;
	for(int l=0;l<=2*n-1;++l)
		for(int r=0;r+l<=2*n-1;++r)
			add(ans,f[1][l][r]);
	cout<<ans<<'\n';
}

你可能感兴趣的:(DP及DP优化)