BZOJ1806: [Ioi2007]Miners 矿工配餐
【传送门:BZOJ1806】
简要题意:
有两个矿洞,有三种食物,给出n个食物的配送顺序,每个食物可以给任意一个矿洞,每个食物送到一个矿洞的收益是这个矿洞最近三次(包括送的那次)食物的种类数
请你经过合理的分配食物使得收益最大
题解:
水题DP
设f[i][t1][t2][t3][t4]为当前已经送了i个食物,且最近两次给第一个矿洞送了第t1和t2种食物(t1比t2更早送),给第二个矿洞送了第t3和t4种食物(t3比t4更早送)能得到的最大收益
假如t1,t2,t3,t4为0,表示当前没有送那么多的餐
转移想想就会了
然后这题卡空间。。
没关系,滚动数组一下就好了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; char st[110000]; int f[2][4][4][4][4]; int a[110000]; int main() { int n; scanf("%d",&n); scanf("%s",st+1); for(int i=1;i<=n;i++) { if(st[i]=='M') a[i]=1; if(st[i]=='F') a[i]=2; if(st[i]=='B') a[i]=3; } memset(f,-1,sizeof(f)); f[0][0][0][0][0]=0; int now=0,last=1; int ans=0; for(int i=1;i<=n;i++) { now^=1;last^=1; for(int t1=0;t1<=3;t1++) { for(int t2=0;t2<=3;t2++) { int d1=0; if(t1!=0&&t2==0) { d1=1;if(t1!=a[i]) d1=2; } else if(t1==0&&t2!=0) { d1=1;if(t2!=a[i]) d1=2; } else if(t1!=0&&t2!=0) { if(t1==t2) { d1=1;if(t1!=a[i]) d1=2; } else { d1=2;if(t1!=a[i]&&t2!=a[i]) d1=3; } } else d1=1; for(int t3=0;t3<=3;t3++) { for(int t4=0;t4<=3;t4++) { int d2=0; if(t3!=0&&t4==0) { d2=1;if(t4!=a[i]) d2=2; } else if(t3==0&&t4!=0) { d2=1;if(t4!=a[i]) d2=2; } else if(t3!=0&&t4!=0) { if(t3==t4) { d2=1;if(t3!=a[i]) d2=2; } else { d2=2;if(t3!=a[i]&&t4!=a[i]) d2=3; } } else d2=1; if(f[last][t1][t2][t3][t4]!=-1) { f[now][t2][a[i]][t3][t4]=max(f[now][t2][a[i]][t3][t4],f[last][t1][t2][t3][t4]+d1); f[now][t1][t2][t4][a[i]]=max(f[now][t1][t2][t4][a[i]],f[last][t1][t2][t3][t4]+d2); ans=max(ans,max(f[now][t2][a[i]][t3][t4],f[now][t1][t2][t4][a[i]])); } } } } } } printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚