成绩单 题解

那年仲夏 提交于 2019-12-09 21:35:54

asd[i][j][l][r]asd[i][j][l][r]表示在第ii个数到第jj个数中取出一些数之后,剩下的数的值在[l,r][l,r]范围内的最小代价

显然asd[i][j][0][0]asd[i][j][0][0]表示将这一段数全部取出的最下代价。

由于n50n\leq 50,考虑对wiw_i进行离散化

l,rl,r离散前的值为x,yx,y

对于asd[i][j][0][0]asd[i][j][0][0],一共有两种情况:

1.一次性全部取完:

asd[i][j][0][0]=a+b×(maxwiwjminwiwj)asd[i][j][0][0]=a+b\times(max_{w_i \sim w_j}-min_{w_i\sim w_j})

2.先取完值不在[l,r][l,r]内的数

asd[i][j][0][0]=asd[i][j][l][r]+a+b×(yx)2asd[i][j][0][0]=asd[i][j][l][r]+a+b\times (y-x)^2

对这两种情况取最小值就行了

对于asd[i][j][l][r]asd[i][j][l][r],考虑枚举区间中的某个点kk,表示吧[i,j][i,j]分为左边的[i,k][i,k]和右边的[k+1,r][k+1,r]

有三种情况:

1.左边的被取完,右边的不取完:

asd[i][j][l][r]=asd[i][k][0][0]+asd[k+1][j][l][r]asd[i][j][l][r]=asd[i][k][0][0]+asd[k+1][j][l][r]

2.左边的不取完,右边的被取完:

asd[i][j][l][r]=asd[i][k][l][r]+asd[k+1][j][0][0]asd[i][j][l][r]=asd[i][k][l][r]+asd[k+1][j][0][0]

3.左边的和右边的都没取完:

asd[i][j][l][r]=asd[i][k][l][r]+asd[k+1][j][l][r]asd[i][j][l][r]=asd[i][k][l][r]+asd[k+1][j][l][r]

对这三种情况取最小值就行了。

初值:

i==j&&lwiri==j\&\&l\leq w_i\leq r时,asd[i][j][l][r]=0asd[i][j][l][r]=0

其余赋值为infinf

#include<bits/stdc++.h>
using namespace std;
#define f1(a,b,c) for(int c=a;c<=b;c++)
#define f2(a,b,c) for(int c=a;c>=b;c--)
#define f3(a,b,c) for(int c=a;c;c=b)
#define so1(a,n) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define itn int
#define ubt int 
#define mp make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
const int twx=55;
const int inf=0x3f3f3f3f;
ll read()
{
    ll sum=0;
    ll flag=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
        {
            flag=-1;
        }
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        sum=((sum*10)+c-'0');
        c=getchar();
    }
    return sum*flag;
}
int n;
int a,b;
int w[twx];
int asd[twx][twx][twx][twx];//设asd[i][j][l][r]表示在第i个数到第j个数中取出一些数之后,剩下的数的值在[l,r]范围内的最小代价 
int c[twx];
int tot;
int p[twx];
bool vis[twx][twx][twx][twx];
void init()
{
	n=read();
	a=read();
	b=read();
	f1(1,n,i)
	{
		c[i]=read();
		w[i]=p[i]=c[i];
	} 
}
int dfs(int i,int j,int l,int r)
{
	if(vis[i][j][l][r])
	{
		return asd[i][j][l][r];
	}
	vis[i][j][l][r]=1;
	asd[i][j][l][r]=inf;
	if(!l&&!r)
	{
		int x=inf;
		int y=-inf;
		int k;
		f1(i,j,k)
		{
			x=min(x,c[k]);
			y=max(y,c[k]);
		}
		asd[i][j][0][0]=a+b*(y-x)*(y-x);
		f1(1,tot,xx)
		{
			f1(1,tot,yy)
			{
				int res=dfs(i,j,xx,yy);
				asd[i][j][0][0]=min(asd[i][j][0][0],res+a+b*(p[yy]-p[xx])*(p[yy]-p[xx]));
			}
		}
		return asd[i][j][0][0];
	}
	else
	{
		if(i==j)
		{
			if(l<=w[i]&&w[i]<=r)
			{
				asd[i][j][l][r]=0;
			}
			return asd[i][j][l][r];
		}
		f1(i,j-1,k)
		{
			asd[i][j][l][r]=min(asd[i][j][l][r],dfs(i,k,l,r)+dfs(k+1,j,l,r));
			asd[i][j][l][r]=min(asd[i][j][l][r],dfs(i,k,0,0)+dfs(k+1,j,l,r));
			asd[i][j][l][r]=min(asd[i][j][l][r],dfs(i,k,l,r)+dfs(k+1,j,0,0)); 
		}
		return asd[i][j][l][r];
	}
}
void work()
{
    so2(p,n)
    tot=unique(p+1,p+n+1)-p-1;
    f1(1,n,i)
    {
    	w[i]=lower_bound(p+1,p+tot+1,c[i])-p;
    }
    printf("%d\n",dfs(1,n,0,0));
}
void print()
{
    
}
int main()
{
    init();
    work();
    print();
	return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!