描述
Consider a positive integer sequence a[1], …, a[n] (n ≥ 3). If for every 2 ≤ i ≤ n-1, a[i-1] + a[i+1] ≥ 2 × a[i] holds, then we say this sequence is beautiful.
Now you have a positive integer sequence b[1], …, b[n]. Please calculate the probability P that the resulting sequence is beautiful after uniformly random shuffling sequence b.
You’re only required to output (P × (n!)) mod 1000000007. (Obviously P × (n!) is an integer)
分析
答案其实求的就是合法的方案总数,
考虑它的限定条件:
a[i−1]+a[i+1]≥2∗a[i]
用图像来表示这个数列:
很容易发现,一旦存在一个波峰:
那么
a[i]>a[i−1],a[i]>a[i+1],即a[i]∗2>a[i−1]+a[i+1]
,一定矛盾
因此,不可能存在波峰情况。
因此,这个数列的图像的大致趋势就可以确定了:
(图中的波谷可能在边界,此时就是一个递增/递减的序列了)
基于这种情况,我们就可以通过DP来解决问题了:
首先将b数组排序,再将其分成两组,
我们设dp[i][j][k][l]表示:
最大值所在的序列最大的数为
bi
最大值不在的序列最大的数为
bj
最大值所在的序列次大的数为
bk
最大值不在的序列次大的数为
bl
转移方程就很好想了:
枚举每一个状态,向其中加入
bi+1
注意:最小值不参与这些计算。
答案就是
不用特别判断 j=k 等非法的情况,因为那些情况中dp值一定为0
因为最小值的取值是任意的,所以设有
K
个最小值,
那么答案就得再乘上
初始状态
dp[1][1][0][0]=1
,这个状态有点非法,但综合一下我考场上的几种写法,这样做相对来说后面好写一点。
因此,在转移的时候就要特别考虑到从边界转移的问题,所以要加几个恶心的max,来保证初始状态能够转移出去。
当时那场hihocoder我就是做了这道垃圾水题,就进了前20,拿了一个滴滴出行的玩偶。
第一次网赛拿奖品,还是挺开心的。这道题我当时调了很久,考试结束前18分钟才做出来(蒟蒻属性暴露无遗),最后半个小时的时候,真心觉得调不出来了,但想了想还是拼了一下,居然过了。不到最后一刻真不能认怂啊。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define SF scanf
#define PF printf
using namespace std;
void Read(int &x){
char c;
bool flag=0;
while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-');
if(c=='-'){ c=getchar();flag=1;}
x=c-'0';
while(c=getchar(),c!=EOF&&c>='0'&&c<='9')x=x*10+c-'0';
if(flag)x=-x;
}
#define MAXN 65
#define MOD 1000000007
long long dp[MAXN][MAXN][MAXN][MAXN];
int n,k,tot;
long long a[MAXN],b[MAXN];
long long jc(long long x){
long long res=1;
while(x){
res*=x;
res%=MOD;
x--;
}
return res%MOD;
}
int main(){
Read(n);
for(int i=1;i<=n;i++)
SF("%lld",&b[i]);
sort(b+1,b+1+n);
int st=1;
for(;b[st]==b[1]&&st<=n;st++);
a[1]=b[1];
for(int i=2;i<=n-st+2;i++)
a[i]=b[st+i-2];
if(st>n){
PF("%lld",jc(st-1));
return 0;
}
n=n-st+2;
dp[1][1][0][0]=1;
for(int i=1;i<n;i++)
for(int j=1;j<max(2,i);j++)
for(int k=0;k<max(1,i);k++)
for(int l=0;l<max(1,j);l++){
if((a[i+1]>=2*a[i]-a[k])||k==0){
dp[i+1][j][i][l]+=dp[i][j][k][l];
dp[i+1][j][i][l]%=MOD;
}
if((a[i+1]>=2*a[j]-a[l])||l==0){
dp[i+1][i][j][k]+=dp[i][j][k][l];
dp[i+1][i][j][k]%=MOD;
}
}
/*for(int i=0;i<=n;i++)
for(int j=0;j<=i;j++)
for(int k=0;k<=i;k++)
for(int l=0;l<=j;l++)
PF("(%lld %d %d %d %d)\n",dp[i][j][k][l],i,j,k,l);*/
long long ans=0;
for(int i=0;i<n;i++)
for(int k=0;k<n;k++)
for(int l=0;l<max(1,i);l++){
ans+=dp[n][i][k][l];
ans%=MOD;
}
PF("%lld",(ans*jc(st-1))%MOD);
}