bzoj1806 [Ioi2007]Miners 矿工配餐

题目链接:bzoj1806
题目大意:
有N辆含3种类型的餐车,分别送往两个煤矿。
每当一个新的餐车到达一个煤矿时,矿工们就会比较这种新的食品和前两次(或者少于两次,如果前面运送食品的次数不足两次)的食品:
• 如果这几次食品车都是同一类型的食品,则矿工们产出一个单位的煤。
• 如果这几次食品车中有两种不同类型的食品,则矿工们产出两个单位的煤。
• 如果这几次食品车中有三种不同类型的食品,则矿工们产出三个单位的煤。
问最大的总产煤量。
N106

题解:
dp…乱来
刷题表以来,这是我第一道想到的dp题QwQ
f[i][x1][x2][y1][y2] 表示准备弄第 i 辆餐车,x1,x2,y1,y2分别记录两个矿场最近两次的状态。转移就很简单啊。

然后我开了个f[N][4][4][4][4]的数组。看了看限制。一算,只能开大概一千六百万的数组,而这个是两千多万的!woc!难道想错了??
翻了翻记录,大家的空间大概都是2N、3N的样子。。。GG
我可能是忽略了字符串的空间大小= =

其实其实滚动一下就好了Orz

话说,我滚动数组每次忘了清居然A了,不过慢好多。
清了的话几百毫秒,没请一秒多快两秒的样子。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 100010

char s[maxn];
int f[2][4][4][4][4];
//0-空 1-M 2-F 3-B
int cal(char c)
{
    if (c=='M') return 1;
    if (c=='F') return 2;
    if (c=='B') return 3;
}
int pd(int x,int y,int z)
{
    if (x==0 && y==0 && z!=0) return 1;
    if (x==0 && y!=0 && y==z) return 1;
    if (x==0 && y!=0 && z!=y) return 2;
    if (x==y && y==z) return 1;
    if ((x==y && x!=z)||((x==z || y==z)&& x!=y)) return 2;
    return 3;
}
int mymax(int x,int y){return (x>y)?x:y;}
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    int n,i,x1,x2,y1,y2,t;
    scanf("%d\n",&n);
    gets(s+1);t=1;
    memset(f,-1,sizeof(f));
    f[0][0][0][0][0]=0;
    for (i=1;i<=n;i++)
    {
        int tt=cal(s[i]);
        for (x1=0;x1<4;x1++)
         for (x2=0;x2<4;x2++)
          for (y1=0;y1<4;y1++)
           for (y2=0;y2<4;y2++)
            if (f[1-t][x1][x2][y1][y2]>=0)
            {
                int num=pd(x1,x2,tt);
                f[t][x2][tt][y1][y2]=mymax(f[t][x2][tt][y1][y2],f[1-t][x1][x2][y1][y2]+num);

                num=pd(y1,y2,tt);
                f[t][x1][x2][y2][tt]=mymax(f[t][x1][x2][y2][tt],f[1-t][x1][x2][y1][y2]+num);
            }
        t=1-t;
        memset(f[t],-1,sizeof(f[t]));
    }
    int ans=0;
    for (x1=0;x1<4;x1++)
     for (x2=0;x2<4;x2++)
      for (y1=0;y1<4;y1++)
       for (y2=0;y2<4;y2++)
        ans=mymax(ans,f[1-t][x1][x2][y1][y2]);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值