bzoj1806[Ioi2007]Miners 矿工配餐

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

原文地址:https://www.cnblogs.com/YuanZiming/p/5720816.html