【高手训练】动态规划

T1.成绩单

期末考试结束了,班主任 老师要将成绩单分发到每位同学手中。

老师共有份成绩单,按照编号从到的顺序叠放在桌子上,其中编号为的成绩单分数为。

成绩单是按照批次发放的。发放成绩单时,老师会从当前的一叠成绩单中抽取连续的一段,让这些同学来领取自己的成绩单。

当这批同学领取完毕后,老师再从剩余的成绩单中抽取连续的一段,供下一批同学领取。

经过若干批次的领取后,成绩单将被全部发放到同学手中。

然而,分发成绩单是一件令人头痛的事情,一方面要照顾同学们的心理情绪,不能让分数相差太远的同学在同一批领取成绩单;

另一方面要考虑时间成本,尽量减少领取成绩单的批次数。

对于一个分发成绩单的方案,我们定义其代价为:

\(a*k+b*\sum_{i=1}^k(max_i-min_i)^2\)

其中,是方案中分发成绩单的批次数,对于第批分发的成绩单,是最高分数,是最低分数。

是给定的评估参数。现在,请你帮助老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉老师。

当然,分发成绩单的批次数是由你决定的。

一道题面比较真实的题目
需要离散化,设状态\(f[i][j][l][r]\)为在[i,j]表示\([i,j]\)区间内取到剩余数字值域为区间\([l,r]\)的最小代价。特别的,令\(f[i][j][0][0]\)表示\([i,j]\)区间取完的最小代价。枚举一个中间点\(k\),将\([l,r]\)分为\([l,k]\)\([k+1,r]\)两个区间进行状态转移取最小值。而显然
\(f[i][j][0][0]=min(f[i][j][l][r]+a+b*(r-l)^2)\)
注意如果是dfs遍历的话不要忘了加记忆化

#include <bits/stdc++.h>
using namespace std;
#define N 55
#define INF 2000000000
#define int long long
//懒得一个一个longlong改过去了...
inline int rf()
{
    int r;int s=0,c;
    for(;!isdigit(c=getchar());s=c);
    for(r=c^48;isdigit(c=getchar());
    (r*=10)+=c^48);
    return s^45?r:-r;
}
int n,a,b,top=1;
int w[N],ww[N];
int ans[N][N];
int f[N][N][N][N];
bool vis[N][N][N][N];
int dfs(int i,int j,int l,int r)
{
    if(vis[i][j][l][r]) return f[i][j][l][r];
    f[i][j][l][r]=INF,vis[i][j][l][r]=1;
    if(l==0&&r==0)//对f[i][j][0][0]进行转移
    {
        int minn=top+1,maxx=0;
        for(int k=i;k<=j;k++)
            minn=min(minn,w[k]),maxx=max(maxx,w[k]);
        for(int k=1;k<=top;k++)
            for(int m=k;m<=top;m++)
            {
                int res=dfs(i,j,k,m);
                if(res==INF) continue;
                f[i][j][l][r]=min(f[i][j][l][r],res+a+b*(ww[m]-ww[k])*(ww[m]-ww[k]));
            }
    }
    else//就是普通的f[i][j][l][r]
    {
        if(i==j)
        {
            if(l<=w[i]&&w[i]<=r) f[i][j][l][r]=0;
            return f[i][j][l][r];
        }
        for(int k=i;k<j;k++)
        {
            f[i][j][l][r]=min(f[i][j][l][r],dfs(i,k,0,0)+dfs(k+1,j,l,r));
            f[i][j][l][r]=min(f[i][j][l][r],dfs(i,k,l,r)+dfs(k+1,j,0,0));
            f[i][j][l][r]=min(f[i][j][l][r],dfs(i,k,l,r)+dfs(k+1,j,l,r));
        }
    }
    return f[i][j][l][r];
}
signed main()
{
    n=rf();
    a=rf(),b=rf();
    for(int i=1;i<=n;i++)
        w[i]=rf(),ww[i]=w[i];
    sort(ww+1,ww+n+1);
    for(int i=2;i<=n;i++)
        if(ww[i]!=ww[i-1]) ww[++top]=ww[i];
    for(int i=1;i<=n;i++)
        w[i]=lower_bound(ww+1,ww+top+1,w[i])-ww;//离散化
    printf("%d\n",dfs(1,n,0,0));
    return 0;
}

T2.字符合并

有一个长度为\(n\)\(01\)串,你可以每次将相邻的\(k\)个字符合并,得到一个新的字符并获得一定分数。

得到的新字符和分数由这\(k\)个字符确定。

你需要求出你能获得的最大分数。

#include <bits/stdc++.h>
using namespace std;
#define N 310
#define mo 998244353
#define int long long
inline int rf()
{
    int r;int s=0,c;
    for(;!isdigit(c=getchar());s=c);
    for(r=c^48;isdigit(c=getchar());
    (r*=10)+=c^48);
    return s^45?r:-r;
}
int n,k,INF;
int c[257],w[257];
int a[N];
int f[N][N][257];
inline void up(int &x,int y){x=x>y?x:y;}
signed main()
{
    n=rf(),k=rf();
    for(int i=1;i<=n;i++)
        a[i]=rf();
    for(int i=0;i<(1<<k);i++)
        c[i]=rf(),w[i]=rf();
    memset(f,128,sizeof(f)),INF=f[0][0][0];
    for(int i=1;i<=n;i++)
        f[i][i][a[i]]=0;
    for(int l=2;l<=n;l++)
        for(int i=1;i<=n-l+1;i++)
        {
            int j=i+l-1,len=j-i;
            while(len>=k) len-=k-1;
            for(int m=j;m>i;m-=k-1)
                for(int S=0;S<(1<<len);S++)
                    if(f[i][m-1][S]!=INF)
                    {
                        if(f[m][j][0]!=INF) up(f[i][j][S<<1],f[i][m-1][S]+f[m][j][0]);
                        if(f[m][j][1]!=INF) up(f[i][j][S<<1|1],f[i][m-1][S]+f[m][j][1]);
                    }
            if(len==k-1)
            {
                int g[2];g[0]=g[1]=INF;
                for(int S=0;S<(1<<k);S++)
                    if(f[i][j][S]!=INF) 
                        g[c[S]]=max(g[c[S]],f[i][j][S]+w[S]);
                f[i][j][0]=g[0];f[i][j][1]=g[1];
            }
        }
    int ans=0;
    for(int i=0;i<(1<<k);i++)
        ans=max(ans,f[1][n][i]);
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luokai-2022/p/12199601.html