1 条题解

  • 0
    @ 2025-8-24 22:33:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar WAWA_QWQ
    这个家伙神经病,什么也没有留下

    搬运于2025-08-24 22:33:08,当前版本为作者最后更新于2024-08-15 08:32:55,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    更好的阅读体验


    很有趣的 DP 题。

    规定 Stjepan 的编号为 00,Ivan 为 11,Gustav 为 22

    定义fi,a,b,c,df_{i,a,b,c,d} 表示当前做到第 ii 个任务,做题选手顺序为 aabbcc,且当前题目由编号为 dd 的人完成时的最优解。

    例:f5,2,0,1,0f_{5,2,0,1,0} 表示做题选手顺序为 Gustav(22),Stjepan(00),Ivan(11),且当前题目是由 Stjepan(00)在完成第 55 道题目时的最优解。

    初始化:一开始将 ff 数组打上 ++\inftyf1,a,b,c,af_{1,a,b,c,a} 显然就等于 da,1d_{a,1}

    转移思路:判断上个任务是由自己做优秀还是由排列中的前一个人完成优秀。(本题核心)

    答案:最后一个任务一定是由排列中的最后一个人完成的,即 fn,a,b,c,cf_{n,a,b,c,c}

    #include<bits/stdc++.h> 
    using namespace std;
    const int maxn=200005;
    int n,d[3][maxn],f[maxn][3][3][3][3],ans=1<<30;
    int read(){
    	char ch=getchar();int ret=0,f=1;
    	while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
    	while(ch>='0'&&ch<='9') ret=ret*10+(ch&15),ch=getchar();
    	return ret*f;
    }
    int main(){
    	n=read();
    	for(int i=0;i<3;i++)
    	for(int j=1;j<=n;j++)
    	  d[i][j]=read();
    	
    	for(int i=0;i<=n;i++)
    	for(int a=0;a<3;a++)
    	for(int b=0;b<3;b++)
    	for(int c=0;c<3;c++)
    	for(int d=0;d<3;d++)
    	  f[i][a][b][c][d]=1<<30;//初始化,用memset会MLE
    	
    	f[1][0][1][2][0]=d[0][1];
    	f[1][0][2][1][0]=d[0][1];
    	f[1][1][0][2][1]=d[1][1];
    	f[1][1][2][0][1]=d[1][1];
    	f[1][2][0][1][2]=d[2][1];
    	f[1][2][1][0][2]=d[2][1];//f[1][a][b][c][a]=a[a][1]:第一个任务只能由排列中的第一个人完成,其最优解为第一个人对于这道题目估计的难度
    	
    	for(int i=2;i<=n;i++){
    		f[i][0][1][2][0]=f[i-1][0][1][2][0]+d[0][i];
    		f[i][1][0][2][1]=f[i-1][1][0][2][1]+d[1][i];
    		f[i][1][2][0][1]=f[i-1][1][2][0][1]+d[1][i];
    		f[i][0][2][1][0]=f[i-1][0][2][1][0]+d[0][i];
    		f[i][2][0][1][2]=f[i-1][2][0][1][2]+d[2][i];
    		f[i][2][1][0][2]=f[i-1][2][1][0][2]+d[2][i];//1至i的任务都是由第一个人完成的,继承前一状态+当前代价即可 
    		if(i<2) continue; 
    		f[i][0][1][2][1]=min(f[i-1][0][1][2][0],f[i-1][0][1][2][1])+d[1][i];
    		f[i][0][2][1][2]=min(f[i-1][0][2][1][0],f[i-1][0][2][1][2])+d[2][i];
    		f[i][1][0][2][0]=min(f[i-1][1][0][2][1],f[i-1][1][0][2][0])+d[0][i];
    		f[i][1][2][0][2]=min(f[i-1][1][2][0][1],f[i-1][1][2][0][2])+d[2][i];
    		f[i][2][0][1][0]=min(f[i-1][2][0][1][2],f[i-1][2][0][1][0])+d[0][i];
    		f[i][2][1][0][1]=min(f[i-1][2][1][0][2],f[i-1][2][1][0][1])+d[1][i];//当前任务由第二个人完成,比较上一个任务是由自己完成好还是别人完成好
    		if(i<3) continue;
    		f[i][0][1][2][2]=min(f[i-1][0][1][2][1],f[i-1][0][1][2][2])+d[2][i];
    		f[i][0][2][1][1]=min(f[i-1][0][2][1][2],f[i-1][0][2][1][1])+d[1][i];
    		f[i][1][0][2][2]=min(f[i-1][1][0][2][0],f[i-1][1][0][2][2])+d[2][i];
    		f[i][1][2][0][0]=min(f[i-1][1][2][0][0],f[i-1][1][2][0][2])+d[0][i];
    		f[i][2][0][1][1]=min(f[i-1][2][0][1][0],f[i-1][2][0][1][1])+d[1][i];
    		f[i][2][1][0][0]=min(f[i-1][2][1][0][0],f[i-1][2][1][0][1])+d[0][i];//当前任务由第三个人完成,比较上一个任务是由自己完成好还是别人完成好
    	}
    	ans=min(ans,f[n][0][1][2][2]);
    	ans=min(ans,f[n][0][2][1][1]);
    	ans=min(ans,f[n][1][0][2][2]);
    	ans=min(ans,f[n][1][2][0][0]);
    	ans=min(ans,f[n][2][0][1][1]);
    	ans=min(ans,f[n][2][1][0][0]);//无论如何,最后一个任务一定是由排列中的最后一个人完成的
    	printf("%d\n",ans); 
    	return 0;
    }
    

    附录:本思路的另一种写法

    Idea:

    https://www.luogu.com.cn/discuss/893769

    排版 & 格式:

    https://www.luogu.com.cn/discuss/602458

    • 1

    信息

    ID
    7126
    时间
    1000ms
    内存
    64MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者