HDU6764 Blood Pressure Game(神级DP)

Gugulu,一个JBer,两年前是ACMer,来到HDOJ,再次参加2020年的多大学培训比赛。然而,每次古古鲁来到区域赛,他总是得到一枚铁质奖牌,并会把这场比赛看成是JB。为了缓解痛苦,古古鲁会去上海迪士尼乐园玩过山车。古古鲁非常喜欢高血压的感觉,这让他觉得自己就像一只快乐的松鸡,忘记了所有错误的答案和超出的时间限制等等。

 

 


我们可以把过山车的路径看作是一个具有不同高度的转折点的列表,它可以表示为一个数组{a1,a2,a3,…,an}大小为n,过山车游戏结束后Gugulu的最终血压被计算为n−1对相邻数组数之间差值的所有绝对值之和,i、 e.∑n−1i=1 | ai−ai+1 |。

 

古古鲁总是获得铁牌,而且总是获得铁牌,这让他一次又一次地坐过山车。然而,随着游戏的增多,他对能使自己快乐的血压值的阈值不断提高。因此,上海迪士尼乐园的过山车已经不能满足古古鲁的需求了。

 

因此,古古鲁决定重新排列{a1,a2,a3,…,an}以使他的血压尽可能高。此外,他还想知道可以达到的血压最大k值和相应的排列数。

 

你,另一个JBer,确信古古鲁足够聪明,可以得到最高的血压。为了挽救古古鲁的生命,事先与合适的心脏病专家预约,计算出正确的答案是非常重要的。你必须解决这个问题!古古鲁的血压已经失控了!

 


输入

输入的第一行包含测试用例数T(1≤T≤5)。T测试用例如下。

 

对于每个测试用例,第一行包含两个整数,n(2≤n≤600)和k(1≤k≤20)。

 

然后,在第二行,有n个整数{a1,a2,a3,…,an}(1≤ai≤106),表示n个原始过山车转弯点。因为它是一个令人兴奋的过山车,所以可以保证数组中的所有n个整数是成对不同的。

 


输出

对于每个测试用例,输出k行。对于第i行(1≤i≤k),打印两个数字wi和ci,其中wi表示可以达到的第i个最大可能血压值,ci表示模109+7的相应排列数。请注意,当第i个最大可能值不存在时,请打印“-1”。

题解:

#include<bits/stdc++.h>
using namespace std;
const int maxn=605;
const int mod=1e9+7;
int t;
int n,m,k;
int a[maxn];
struct qnode {
    int x,y;
    qnode () {
        
    }
    qnode (int xx,int yy) {
        x=xx;
        y=yy;
    }
    bool operator < (const qnode &r) const {
        return x>r.x;
    }
};
struct inFo {
    int cnt;
    qnode v[maxn];
    void clr () {cnt=0;}
    void add (int A,int B) {
        v[++cnt]=qnode(A,B);
    }
    void fix () {
        sort(v+1,v+cnt+1);
        int i,j,k=0;
        for (i=1;i<=cnt;i=j) {
            int tt=0;
            for (j=i;j<=cnt&&v[i].x==v[j].x;j++) tt=(tt+v[j].y)%mod;
            v[++k]=qnode(v[i].x,tt);
            if (k>=m) break;
        }
        cnt=k;
    }
}f[2][maxn][3];
int main () {
    scanf("%d",&t);
    while (t--) {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",a+i);
        sort(a+1,a+n+1);
        for (int i=0;i<2;i++)
            for (int j=0;j<=n;j++)
                for (int k=0;k<3;k++)
                    f[i][j][k].clr();
        f[1][1][0].add(0,1);
        f[1][1][1].add(0,2);
        int tt=1;
        for (int i=1;i<n;i++) {
            for (int j=0;j<=n;j++)
                for (int k=0;k<3;k++)
                    f[tt^1][j][k].clr();
            for (int j=0;j<=n;j++)
                for (int k=0;k<3;k++) {
                    f[tt][j][k].fix();
                    int cnt=f[tt][j][k].cnt;
                    if (!cnt) continue;
                    int base=(a[i+1]-a[i])*(j*2-k);
                    for (int l=1;l<=cnt;l++) {
                        int A=base+f[tt][j][k].v[l].x;
                        int B=f[tt][j][k].v[l].y;
                        if (j+1>k)
                            f[tt^1][j+1][k].add(A,1ll*B*(j+1-k)%mod);
                        if (j>1)
                            f[tt^1][j-1][k].add(A,1ll*B*(j-1)%mod);
                        if (j*2>k)
                            f[tt^1][j][k].add(A,1ll*B*(j*2-k)%mod);
                        if (k<2) {
                            f[tt^1][j+1][k+1].add(A,1ll*B*(2-k)%mod);
                            f[tt^1][j][k+1].add(A,1ll*B*(2-k)%mod);
                        } 
                    }
                }
            tt^=1;
        }
        f[tt][1][2].fix();
        int i;
        for (i=1;i<=f[tt][1][2].cnt&&i<=m;i++) {
            printf("%d %d\n",f[tt][1][2].v[i].x,(f[tt][1][2].v[i].y%mod+mod)%mod);
        }
        for (;i<=m;i++) printf("-1\n");
    }
}

 

posted @ 2020-09-17 16:37  zlc0405  阅读(264)  评论(0编辑  收藏  举报