bzoj1806[Ioi2007]Miners 矿工配餐
题意:
现有两个煤矿,有三种类型的食品车。每当一个新的食品车到达煤矿时,矿工们就会比较这种新的食品和前两次(或者少于两次,如果前面运送食品的次数不足两次)的食品。如果这几次食品车都是同一类型的食品,则矿工们产出一个单位的煤; 如果这几次食品车中有两种不同类型的食品,则矿工们产出两个单位的煤;如果这几次食品车中有三种不同类型的食品,则矿工们产出三个单位的煤。 预先已知食品车的类型及其被配送的顺序,求通过分配食品车去的煤矿得到的最大产煤量。
题解:
dp,f[i][a][b][c][d]表示送第i辆车来时矿洞1的前两次吃a和b,矿洞2的前两次吃c和d,当b或d为0表示该矿洞只送过一辆车,当a、b或c、d为0时表示该矿洞没送过车。i可以滚动掉,同时i需倒序枚举。求矿工采煤量的分类讨论比较复杂,具体看代码。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define dec(i,j,k) for(int i=j;i>=k;i--) 6 #define maxn 100010 7 using namespace std; 8 9 int cg(char a){ 10 if(a=='M')return 1;else if(a=='F')return 2;else if(a=='B')return 3; 11 } 12 int f[maxn],n,x[4][4][4][4],y[4][4][4][4]; char s[maxn]; 13 int main(){ 14 scanf("%d",&n); scanf("%s",s+1); 15 inc(i,1,n){if(s[i]=='M')f[i]=1; if(s[i]=='F')f[i]=2; if(s[i]=='B')f[i]=3;} memset(x,0,sizeof(x)); 16 dec(i,n,1){ 17 memset(y,0,sizeof(y)); 18 inc(j1,0,3)inc(j2,0,3)inc(j3,0,3)inc(j4,0,3){ 19 if((j1&&!j2)||(j3&&!j4))continue; int plus1,plus2; 20 if((!j1&&!j2)||(!j1&&j2==f[i])||(j1==j2&&j2==f[i]))plus1=1;else 21 if(j1!=j2&&j2!=f[i]&&j1!=f[i]&&j1&&j2)plus1=3;else plus1=2; 22 if((!j3&&!j4)||(!j3&&j4==f[i])||(j3==j4&&j4==f[i]))plus2=1;else 23 if(j3!=j4&&j4!=f[i]&&j3!=f[i]&&j3&&j4)plus2=3;else plus2=2; 24 y[j1][j2][j3][j4]=max(x[j2][f[i]][j3][j4]+plus1,x[j1][j2][j4][f[i]]+plus2); 25 } 26 swap(x,y); 27 } 28 printf("%d",x[0][0][0][0]); return 0; 29 }
20160702