hihocoder#1596 : Beautiful Sequence

#1596 : Beautiful Sequence

时间限制:11000ms

单点时限:1000ms

内存限制:256MB

描述

对于一个正整数列a[1], ... , a[n] (n ≥ 3),如果对于所有2 ≤ i ≤ n - 1,都有a[i-1] + a[i+1] ≥ 2 × a[i],则称这个数列是美丽的。

现在有一个正整数列b[1], ..., b[n],请计算:将b数列均匀随机打乱之后,得到的数列是美丽的概率P。

你只需要输出(P × (n!))mod 1000000007即可。(显然P × (n!)一定是个整数)

输入

第一行一个整数n。 (3 ≤ n ≤ 60)
接下来n行,每行一个整数b[i]。 (1 ≤ b[i] ≤ 1000000000)

输出

输出(P × (n!))mod 1000000007。

样例输入

4
1
2
1
3

样例输出

8

EmacsNormalVim

 GCC G++ C# Java Python2 

 

题解:

这题没深入思考真的要凉。。

因为条件a[i-1] + a[i+1] ≥ 2 × a[i],可化简成a[i+1]-a[i]>=a[i]-a[i-1]

所以最后求的数列一定是先递减后不变后递增的 
拆成2个数列,dp 
f[i][j][k][l]f[i][j][k][l] 表示左端的两个数是 i 和 j,右端的是 k 和 l 的方案数 
最小值有 k 个重复则乘上 k!。非最小值至多只能有 2 次重复(有谁能给我解释下这段话!!!) 
初始状态为数列均为最小值那个值

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,i,j,k,l,ii,a[61],f[61][61][61][61],p=1000000007;
ll ans,sum;
int main(){
	scanf("%lld",&n);
	for(i=1;i<=n;i++)scanf("%lld",&a[i]);
	sort(a+1,a+n+1);
	i=1;
	ans=1;
	while(i<=n&&a[i]==a[1]){
		ans=(1ll*ans*i)%p;
		i++;
	}
	ii=i-1;
	if(i>n){
		printf("%lld",ans);
		return 0;
	}
	//printf("%lld\n",ans);
	f[ii][ii][ii][ii]=1;
	for(i=ii;i<n;i++)
	 for(j=1;j<=i;j++)
	  for(k=1;k<=i;k++)
	   for(l=1;l<=i;l++){
	   	if(!f[i][j][k][l])continue;
	   	if(a[i+1]-a[i]>=a[i]-a[j]){
	   		f[i+1][i][k][l]=(f[i+1][i][k][l]+f[i][j][k][l])%p;
	   	}
	   	if(a[i+1]-a[k]>=a[k]-a[l])
	   	 f[i+1][k][i][j]=(f[i+1][k][i][j]+f[i][j][k][l])%p;
	   }
	sum=0;   
	for(i=1;i<=n;i++)
	 for(j=1;j<=n;j++)
	  for(k=1;k<=n;k++)
	  sum=(sum+1ll*f[n][i][j][k])%p;
	printf("%lld",ans*sum%p);  
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/81124162