[HihoCoder1596]Beautiful Sequence

题目大意:

(n(nle60))个数(A_{1sim n}),将这些数随机打乱,问最后构成的数列满足对于所有的(2le ile n-1),都有(2A_ile A_{i-1}+A_{i+1})的概率。

思路:

显然题目要求的是构成下凸函数的概率。

将所有数排序,考虑最小值在中间,往两遍加数。

(f[i][j][k][l])表示左边第一个数是(i),左边第二个数是(j),右边第一个数是(k),右边第二个数是(l)的方案数。对于每个状态,枚举新增的数放左边或右边即可。

注意特殊处理一开始的边界情况。

时间复杂度(mathcal O(n^4))

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
typedef long long int64;
const int N=61,mod=1e9+7;
int a[N],f[N][N][N][N];
int main() {
	int n=getint();
	for(register int i=1;i<=n;i++) a[i]=getint();
	std::sort(&a[1],&a[n]+1);
	int cnt=0;
	for(register int i=1;i<=n&&a[i]==a[1];i++) cnt++;
	for(register int i=cnt;i<=n;i++) a[i-cnt+1]=a[i];
	a[0]=a[1];
	n-=cnt-1;
	for(register int i=f[1][0][1][0]=1;i<=cnt;i++) {
		f[1][0][1][0]=(int64)f[1][0][1][0]*i%mod;
	}
	for(register int i=1;i<n;i++) {
		for(register int j=0;j<i;j++) {
			for(register int k=1;k<n;k++) {
				for(register int l=0;l<k;l++) {
					const int t=std::max(i,k)+1;
					if(a[i]*2<=a[t]+a[j]) {
						(f[t][i][k][l]+=f[i][j][k][l])%=mod;
					}
					if(a[k]*2<=a[t]+a[l]) {
						(f[i][j][t][k]+=f[i][j][k][l])%=mod;
					}
				}
			}
		}
	}
	int ans=0;
	for(register int i=0;i<=n;i++) {
		for(register int j=0;j<=n;j++) {
			for(register int k=0;k<=n;k++) {
				for(register int l=0;l<=n;l++) {
					if(i==n||j==n||k==n||l==n) {
						(ans+=f[i][j][k][l])%=mod;
					}
				}
			}
		}
	}
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/skylee03/p/9477831.html