题目链接:bzoj1806
题目大意:
有N辆含3种类型的餐车,分别送往两个煤矿。
每当一个新的餐车到达一个煤矿时,矿工们就会比较这种新的食品和前两次(或者少于两次,如果前面运送食品的次数不足两次)的食品:
• 如果这几次食品车都是同一类型的食品,则矿工们产出一个单位的煤。
• 如果这几次食品车中有两种不同类型的食品,则矿工们产出两个单位的煤。
• 如果这几次食品车中有三种不同类型的食品,则矿工们产出三个单位的煤。
问最大的总产煤量。
N≤106
题解:
dp…乱来
刷题表以来,这是我第一道想到的dp题QwQ
设
f[i][x1][x2][y1][y2]
表示准备弄第
i
辆餐车,
然后我开了个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;
}