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