【DP】hihocoder1596 Beautiful Sequence

描述

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[i1]+a[i+1]2a[i]
用图像来表示这个数列:
【DP】hihocoder1596 Beautiful Sequence_第1张图片
很容易发现,一旦存在一个波峰:
那么 a[i]>a[i1],a[i]>a[i+1],a[i]2>a[i1]+a[i+1] ,一定矛盾
因此,不可能存在波峰情况。

因此,这个数列的图像的大致趋势就可以确定了:
【DP】hihocoder1596 Beautiful Sequence_第2张图片
(图中的波谷可能在边界,此时就是一个递增/递减的序列了)

基于这种情况,我们就可以通过DP来解决问题了:
首先将b数组排序,再将其分成两组,
我们设dp[i][j][k][l]表示:
最大值所在的序列最大的数为 bi
最大值不在的序列最大的数为 bj
最大值所在的序列次大的数为 bk
最大值不在的序列次大的数为 bl

转移方程就很好想了:
枚举每一个状态,向其中加入 bi+1

dp[i+1][j][i][l]+=dp[i][j][k][l]

dp[i+1][i][j][k]+=dp[i][j][k][l]

注意:最小值不参与这些计算。

答案就是

0jn,0k<n0<l<jdp[n][j][k][l]

不用特别判断 j=k 等非法的情况,因为那些情况中dp值一定为0

因为最小值的取值是任意的,所以设有 K 个最小值,
那么答案就得再乘上 K

初始状态 dp[1][1][0][0]=1 ,这个状态有点非法,但综合一下我考场上的几种写法,这样做相对来说后面好写一点。
因此,在转移的时候就要特别考虑到从边界转移的问题,所以要加几个恶心的max,来保证初始状态能够转移出去。
这里写图片描述


当时那场hihocoder我就是做了这道垃圾水题,就进了前20,拿了一个滴滴出行的玩偶。
第一次网赛拿奖品,还是挺开心的。这道题我当时调了很久,考试结束前18分钟才做出来(蒟蒻属性暴露无遗),最后半个小时的时候,真心觉得调不出来了,但想了想还是拼了一下,居然过了。不到最后一刻真不能认怂啊。

#include
#include
#include
#include
#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;ifor(int j=1;j2,i);j++)
            for(int k=0;k1,i);k++)
                for(int l=0;l1,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;ifor(int k=0;kfor(int l=0;l1,i);l++){
                ans+=dp[n][i][k][l];
                ans%=MOD;   
            }
    PF("%lld",(ans*jc(st-1))%MOD);
}

你可能感兴趣的:(DP)