Luogu P1373 小a和uim之大逃离【dp】By cellur925
$50pts$:容易设计出状态$f[i][j][l][r][st]$表示当前的这个人在($i$,$j$),小a和uim魔瓶中的含量分别为$l$,$r$,当$st=0$表明现在是小a在吃,当$st=1$表明现在是uim吃(方案数)。注意赋初值为$f[i][j][mapp[i][j]][0][0]=1$。因为是从小a开始吃的。转移方程比较显然&麻烦,就写在代码里了。
但是还是有一些坑点的。比如模数是$k+1$,用刷表法(从当前状态推到之后状态)来防止出现负数。还和学长博客学到了一个神奇的方法:
void zy(int &x,int &y) { x=(x+y)%moder; }
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 const int moder=1e9+7; 6 7 int n,m,k,ans; 8 int mapp[200][200],f[200][200][20][20][2]; 9 10 void zy(int &x,int &y) 11 { 12 x=(x+y)%moder; 13 } 14 15 int main() 16 { 17 scanf("%d%d%d",&n,&m,&k); 18 k++; 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=m;j++) 21 scanf("%d",&mapp[i][j]); 22 for(int i=1;i<=n;i++) 23 for(int j=1;j<=m;j++) 24 f[i][j][mapp[i][j]][0][0]=1; 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=m;j++) 27 for(int l=0;l<=k-1;l++) 28 for(int r=0;r<=k-1;r++) 29 { 30 zy(f[i+1][j][(l+mapp[i+1][j])%k][r][0],f[i][j][l][r][1]); 31 zy(f[i][j+1][(l+mapp[i][j+1])%k][r][0],f[i][j][l][r][1]); 32 zy(f[i+1][j][l][(r+mapp[i+1][j])%k][1],f[i][j][l][r][0]); 33 zy(f[i][j+1][l][(r+mapp[i][j+1])%k][1],f[i][j][l][r][0]); 34 if(l==r) (ans+=f[i][j][l][r][1])%=moder; 35 } 36 printf("%d",ans); 37 return 0; 38 }
$100pts$:上面那个算法的复杂度是$O(n*m*k*k)$,复杂度显然会爆炸。考虑对dp进行优化,有优化状态和优化转移两种方法。状态貌似不能再优化了。
学长:那么这题的转移方程没有最值,没有单调性,那么我们只能优化状态。
考虑设计这样一个状态:$f[i][j][od][st]$表示当前的这个人在($i$,$j$),小a和uim的魔瓶内含量差为$od$的方案数。与之前有相似的转移方程及初值。这样我们的复杂度就是$O(n*m*k)$,可以过。
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 const int moder=1e9+7; 6 7 int n,m,k,ans; 8 int mapp[900][900],f[850][850][20][2]; 9 10 void zy(int &x,int &y) 11 { 12 x=(x+y)%moder; 13 } 14 15 int main() 16 { 17 scanf("%d%d%d",&n,&m,&k); 18 k++; 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=m;j++) 21 scanf("%d",&mapp[i][j]); 22 for(int i=1;i<=n;i++) 23 for(int j=1;j<=m;j++) 24 f[i][j][mapp[i][j]][0]=1; 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=m;j++) 27 for(int od=0;od<=k-1;od++) 28 { 29 zy(f[i+1][j][(od+mapp[i+1][j]+k)%k][0],f[i][j][od][1]); 30 zy(f[i][j+1][(od+mapp[i][j+1]+k)%k][0],f[i][j][od][1]); 31 zy(f[i+1][j][(od-mapp[i+1][j]+k)%k][1],f[i][j][od][0]); 32 zy(f[i][j+1][(od-mapp[i][j+1]+k)%k][1],f[i][j][od][0]); 33 if(od==0) (ans+=f[i][j][od][1])%=moder; 34 } 35 printf("%d",ans); 36 return 0; 37 }
独立意志与自由思想是必须争的,且须以生死力争。