bzoj4897: [Thu Summer Camp2016]成績單

Description
期末考試結束了,班主任L老師要將成績單分發到每位同窗手中。L老師共有n份成績單,按照編號從1到n的順序疊
放在桌子上,其中編號爲i的成績單分數爲w_i。成績單是按照批次發放的。發放成績單時,L老師會從當前的一疊
成績單中抽取連續的一段,讓這些同窗來領取本身的成績單。當這批同窗領取完畢後,L老師再從剩餘的成績單中
抽取連續的一段,供下一批同窗領取。通過若干批次的領取後,成績單將被所有發放到同窗手中。然而,分發成績
單是一件使人頭痛的事情,一方面要照顧同窗們的心理情緒,不能讓分數相差太遠的同窗在同一批領取成績單;另
一方面要考慮時間成本,儘可能減小領取成績單的批次數。對於一個分發成績單的方案,咱們定義其代價爲:

其中,k是方案中分發成績單的批次數,對於第i批分發的成績單,〖max〗_i是最高分數,〖min〗_i是最低分數。
a,b是給定的評估參數。如今,請你幫助L老師找到代價最小的分發成績單的方案,並將這個最小的代價告訴L老師
。固然,分發成績單的批次數k是由你決定的。php

Input
第一行包含一個正整數n,表示成績單的數量。
第二行包含兩個非負整數a,b,表示給定的評估參數。
第三行包含n個正整數w_i,表示第i張成績單上的分數。ios

Output
僅一個正整數,表示最小的代價是多少。git

Sample Input
10ide

3 1spa

7 10 9 10 6 7 10 7 1 2code

Sample Output
15blog

【樣例數聽說明】
第1批:第2至4份成績單,落差值爲1,剩餘成績單爲76710712;ip

第2批:第4份成績單,落差值爲0,剩餘成績單爲767712;get

第3批:第1至4份成績單,落差值爲1,剩餘成績單爲12;string

第4批:剩餘的2份成績單,落差值爲1。

總代價爲4×3+(1^2+0^2+1^2+1^2)×1=15。

HINT
n<=50, a<=100, b<=10, w_i<=1000

思路:

注意是從中間抽,不然就太簡單了。
每次抽確定是一個子序列,且中間的空都是被抽空了。
設g[l][r]表示區間[l,r]被抽空的最小代價,f[l][r][i][j]表示區間[l,r]最後一抽最小值爲i,
最大值爲j,且強制要選a[l],a[r]的最小代價,
f[l][r][i][j]+g[r+1][R-1]→f[l][R][min(i,a[R])][max(j,a[R])])
f[l][r][i][j]+g[r+1][R]+A+B*(j-i)^2→g[l][R]

代碼+雙倍經驗

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<vector>
#define ll long long
using namespace std;
inline int read()
{
   int s=0,w=1;
   char ch=getchar();
   while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
   while(isdigit(ch)) s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int n,mx,A,B,a[55],b[55],f[55][55][55][55],g[55][55];
void checkmin(int &x,int y)
{
    x=x<y?x:y;
}
int main()
{
    n=read(),A=read(),B=read();
    for(int i=1;i<=n;i++)
    a[i]=b[i]=read();
    sort(b+1,b+n+1),mx=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
    a[i]=lower_bound(b+1,b+mx+1,a[i])-b;
    memset(f,0x3f3f3f3f,sizeof f),memset(g,0x3f3f3f3f,sizeof g);
    for(int i=1;i<=n;i++)
    f[i][i][a[i]][a[i]]=0,g[i][i]=A,g[i][i-1]=0;
    g[n+1][n]=0;
    for(int l=n;l;l--)
    for(int r=l;r<=n;r++)
    for(int i=1;i<=mx;i++)
    for(int j=i;j<=mx;j++)
    if(f[l][r][i][j]!=0x3f3f3f3f)
    {
        for(int nr=r+1;nr<=n;nr++)
        checkmin(f[l][nr][min(i,a[nr])][max(j,a[nr])],f[l][r][i][j]+g[r+1][nr-1]);
        for(int nr=r;nr<=n;nr++)
        g[l][nr]=min(g[l][nr],f[l][r][i][j]+g[r+1][nr]+A+B*(b[j]-b[i])*(b[j]-b[i]));
    }
    printf("%d",g[1][n]);
    return 0;
}
View Code
相關文章
相關標籤/搜索