【动态规划/递推】BZOJ1806[IOI2007]- Miners
IOI历史上的著名水题,我这种蒟蒻都能写的东西。
【思路】
用1、2、3分别代替三种食物,0表示当前矿井没有食物。f[i][a][b][c][d]当前第i个食物,矿1的食物顺序由上至下为a,b;矿2的食物顺序由上至下为c,d。
判断产物数量的方法很巧妙,由下至上a,b,c。初始时默认投入一个食物至少生产一单位,如果a为有食物且与bc不同,则加一单位;如果b为有食物且与c不同,再加一个单位。最后加一个滚动数组就可以了。
【错因】
1.因为a,b,c,d大小范围是0..3,但是我把下标范围写3!一定要写4!我就是一不小心写错了,居然改了两个晚上,完全没有考虑到错因在这里....
2.还有初始化的时候只有f[0][0][0][0][0]是0,不要把所有第一位是0的都写成0了..
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int MAXN=100000+500; 6 int n; 7 int food[MAXN]; 8 int f[2][4][4][4][4];//f[i][a][b][c][d]当前第i个食物,矿1的食物顺序由上至下为a,b;矿2的食物顺序由上至下为c,d。 9 10 int compare(int x,int y,int z) 11 { 12 int t=1; 13 if (x!=0 && x!=y && x!=z) t++; 14 if (y!=0 && y!=z) t++; 15 return t; 16 } 17 18 int main() 19 { 20 scanf("%d",&n); 21 getchar(); 22 for (int i=0;i<n;i++) 23 { 24 char c; 25 scanf("%c",&c); 26 if (c=='M') food[i]=1; 27 if (c=='F') food[i]=2; 28 if (c=='B') food[i]=3; 29 } 30 31 memset(f,-1,sizeof(f)); 32 f[0][0][0][0][0]=0;33 int ans=-1; 34 for (int i=0;i<n;i++) 35 for (int a=0;a<=3;a++) 36 for (int b=0;b<=3;b++) 37 for (int c=0;c<=3;c++) 38 for (int d=0;d<=3;d++) 39 { 40 if (f[i%2][a][b][c][d]==-1) continue; 41 int add1=compare(b,a,food[i]),add2=compare(d,c,food[i]); 42 43 int x=food[i]; 44 f[(i+1)%2][x][a][c][d]=max(f[(i+1)%2][x][a][c][d],f[i%2][a][b][c][d]+add1); 45 f[(i+1)%2][a][b][x][c]=max(f[(i+1)%2][a][b][x][c],f[i%2][a][b][c][d]+add2); 46 if ((i==n-1) && (f[(i+1)%2][x][a][c][d]>ans)) ans=f[(i+1)%2][x][a][c][d]; 47 if ((i==n-1) && (f[(i+1)%2][a][b][x][c]>ans)) ans=f[(i+1)%2][a][b][x][c]; 48 } 49 cout<<ans<<endl; 50 return 0; 51 }