Loj#2292.「THUSC 2016」成绩单 | wzf2000's blog

Loj#2292.「THUSC 2016」成绩单

Loj#2292.「THUSC 2016」成绩单 题解

题意:

  • 略。

题解:

  • 考虑用 $f[l][r][i][j]$ 表示区间 $[l,r]$,最后一次取的目前最大值为 $i$,最小值为 $j$ 除最后一次的最小总代价。
  • $g[l][r]$ 表示取完区间 $[l,r]$ 的最小总代价。
  • 有两种转移:
    • 将 $f[l][r][i][j]$ 最后一次取的完成:$g[l][k]=\min(g[l][k],f[l][r][i][j]+g[r+1][k]+a+b\times (i-j)^2)$。
    • 将 $f[l][r][i][j]$ 新扩展一次:$f[l][k][\max(i,w[k])][\min(j,w[k])]=\min(f[l][k][\max(i,w[k])][\min(j,w[k])],f[l][r][i][j]+g[r+1][k])$。
  • 然后离散化一下权值。
  • 时间复杂度 $O(n^4)$。

代码:

#include <bits/stdc++.h>
#define gc getchar()
using namespace std;
const int N=59;
int a[N],n,val[N],A,B,f[N][N][N][N],g[N][N];
vector<int> q;
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return s*x;
}
void up(int &x,int y)
{
    x=min(x,y);
}
int main()
{
    n=read(),A=read(),B=read();
    for (int i=1;i<=n;i++) a[i]=read(),q.push_back(a[i]);
    sort(q.begin(),q.end());
    q.erase(unique(q.begin(),q.end()),q.end());
    for (int i=1;i<=n;i++)
        a[i]=lower_bound(q.begin(),q.end(),a[i])-q.begin()+1;
    memset(f,63,sizeof(f)),memset(g,63,sizeof(g));
    for (int i=1;i<=n;i++)
        f[i][i][a[i]][a[i]]=0,g[i+1][i]=0;
    g[1][0]=0;
    for (int l=n;l;--l)
        for (int r=l;r<=n;++r)
            for (int i=1;i<=n;i++)
                for (int j=1;j<=i;j++)
                {
                    if (f[l][r][i][j]==0x3f3f3f3f) continue;
                    for (int k=r+1;k<=n;k++)
                        up(f[l][k][max(i,a[k])][min(j,a[k])],f[l][r][i][j]+g[r+1][k-1]);
                    for (int k=r;k<=n;k++)
                        up(g[l][k],f[l][r][i][j]+g[r+1][k]+A+B*(q[i-1]-q[j-1])*(q[i-1]-q[j-1]));
                }
    printf("%d\n",g[1][n]);
    return 0;
}