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 }
50 pts

$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 }
AC

 

posted @ 2018-10-05 18:02  cellur925&Chemist  阅读(182)  评论(0编辑  收藏  举报