【bzoj 1806/CS 1801】矿工配餐 IOI2007(五维DP+滚动数组)


楼下是传送门:
http://www.lydsy.com/JudgeOnline/problem.php?id=1806

Description

现有两个煤矿,每个煤矿都雇用一组矿工。采煤工作很辛苦,所以矿工们需要良好饮食。每当一辆食品车到达煤矿时,矿工们便会产出一定数量的煤。有三种类型的食品车:肉车,鱼车和面包车。 矿工们喜欢变化的食谱。如果提供的食品能够不断变化,他们的产煤量将会增加。每当一个新的食品车到达煤矿时,矿工们就会比较这种新的食品和前两次(或者少于两次,如果前面运送食品的次数不足两次)的食品,并且: • 如果这几次食品车都是同一类型的食品,则矿工们产出一个单位的煤。 • 如果这几次食品车中有两种不同类型的食品,则矿工们产出两个单位的煤。 • 如果这几次食品车中有三种不同类型的食品,则矿工们产出三个单位的煤。 预先已知食品车的类型及其被配送的顺序。通过确定哪车食品送到哪个煤矿可以影响产煤量。食品车不能被拆分,每个食品车必须被全部送到一个或另一个煤矿。两个煤矿也并不要求接收相同数量的食品车(事实上,也允许将所有食品车都送到一个煤矿)。 任务 给出食品车的类型及其被配送的顺序,要求你写一个程序,确定哪个食品车应被送到煤矿1,哪个食品车应被送到煤矿2,以使得两个煤矿的产煤量的总和最大。

Input

输入的第一行包含一个整数N (1 ≤ N ≤ 100 000), 表示食品车的数目。 第二行包含一个由N个字符组成的字符串,按照配送顺序依次表示食品车配送的食品的类型。每个字符是以下三个大写字母之一:’M’ (表示肉类), ‘F’ (表示鱼类) 或 ‘B’ (表示面包)。

Output

输出一个整数,表示最大的总产煤量。 评分 在45分的测试数据中,食品车的数目至多为20

Sample Input

6
MBMFFB

Sample Output

12

思路


五维DP只要不是很丧病,一般就是第一维枚举位置状态,第二三维表示第一个情况的选择状态,第四五维表示第二个情况的选择状态,最终用总的状态求解
多用于求相同的两者的符合题意状态之和的最大或最小值
在本题中第一位枚举的是第几辆车,二三维是第一个矿洞,四五维是第二个矿洞,分表表示了数量和状态
开始的时候预处理一下每个种类以避免重复等等,接着用一个check函数,判断是否满足题目中给定的条件
最后进行dp比较取更大的作为答案
能水过Codevs的数据的TLE…..
http://codevs.cn/problem/1801/
代码如下:

//TLE
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
#define ri register int
const int sz = 1000010;
inline void read(int &x){
    x=0;bool fl=0;char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') fl=1;c=getchar();}
    while(c>='0'&&c<='9')
    {x=x*10+c-'0';c=getchar();}
    if(fl) x*=-1;
}
inline int check(int a,int b,int c)
{
    if(a==0&&b==0) return 1;
    if(a==0) return 1+(b!=c);//代表如果b!=c返回1 
    if(a==b&&b==c) return 1;
    if(a==b||b==c||a==c) return 2;
    return 3;
}
int t[sz],n,f[sz][4][4][4][4];
char s[sz];
int dp(int pos,int a,int b,int x,int y)
{
    if(pos==n+1) return 0;
    if(f[pos][a][b][x][y]!=-1)
        return f[pos][a][b][x][y];
    return f[pos][a][b][x][y]=max(dp(pos+1,b,t[pos],x,y)+check(a,b,t[pos]),dp(pos+1,a,b,y,t[pos])+check(x,y,t[pos]));
}
int main()
{
    read(n);
    scanf("%s",s);
    for(ri i=0;i<n;++i)//!从0开始读 
        if( s[i] == 'B' ) t[i+1] = 1;
        else if( s[i] == 'M' ) t[i+1] = 2;
        else t[i + 1] = 3;
    memset(f,-1,sizeof(f));
    cout<<dp(1,0,0,0,0);
    return 0;
}


但是上面的只能水过10000的数据,对于加强的100000数据无可奈何,惨遭三遍TLE,各种优化卡常献祭秒数却还是难以逃脱这一点
最后各种泪奔直到看到黄学长博客里记录%%%
http://hzwer.com/3645.html
“dp加个滚动数组就差不多了”
浔阳 DP 无滚动,一句惊醒梦中人;
垂死病中惊坐起,谈笑风生又一年
这里的f[i][a1][a2][b1][b2]表示发放第i份食品后第一矿洞最近的食品为 a1 a2,b1 b2同理,读入的时候判断成为什么值,具体的check还是要具题目来自己分析分析,毕竟这个还是比较好弄的
代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline void read(int &x){
    x=0;bool fl=1;char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') fl=-1;c=getchar();}
    while(c>='0'&&c<='9')
    {x=x*10+c-'0';c=getchar();}
    x*=fl;
}
char ch[100010];
int f[5][4][4][4][4],ans,n;
inline int getint(char c)
{
    if(c=='M')return 1;
    else if(c=='F')return 2;
    else return 3;
}
inline int check(int a,int b,int c)
{
    if(a==0&&b==0) return 1;
    if(a==0) return 1+(b!=c);//代表如果b!=c返回1 
    if(a==b&&b==c) return 1;
    if(a==b||b==c||a==c) return 2;
    return 3;
}
int main()
{
    memset(f,-1,sizeof(f));
    f[0][0][0][0][0]=0;
    read(n);
    scanf("%s",ch);
    for(int i=0;i<n;i++)
     for(int a1=0;a1<=3;a1++)
      for(int a2=0;a2<=3;a2++)
       for(int b1=0;b1<=3;b1++)
        for(int b2=0;b2<=3;b2++)
        {
            int x=i%4,y=(i+1)%4;
            if(f[x][a1][a2][b1][b2]==-1)
                continue;
            int t=getint(ch[i]),add;
            add=check(a1,a2,t);
                f[y][a2][t][b1][b2]=
                max(f[y][a2][t][b1][b2],f[x][a1][a2][b1][b2]+add);
            add=check(b1,b2,t);
                f[y][a1][a2][b2][t]=
                max(f[y][a1][a2][b2][t],f[x][a1][a2][b1][b2]+add);
        }
    for(int a1=0;a1<=3;a1++)
     for(int a2=0;a2<=3;a2++)
      for(int b1=0;b1<=3;b1++)
       for(int b2=0;b2<=3;b2++)
        ans=max(ans,f[n%4][a1][a2][b1][b2]);//滚啊滚找回失去的时间【雾】
    printf("%d",ans);
    return 0;
}
发布了75 篇原创文章 · 获赞 80 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36693514/article/details/78279460