#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);
}