Codeforces 1225E: Rock Is Push dp+前缀和

题意

给你一个地图,你可以推箱子,不能推出界外,问从 ( 1 , 1 ) (1,1) ( n , n ) (n,n) 的方案数

分析

一开始看完题目推箱子发现没有什么思路
我们抓住性质,如果一个格子,已经有一次从上面把箱子推下来了,就不可能从左边再推过去
其实我们走的就是横竖横竖这样的路线

再考虑一个问题,我们可以确定一个格子可以从左边过来,但是推了多少个箱子过来,我们是不是要记录一下是从哪个位置开始一直往左推的呢?

我们还可以想到,只要你拐弯了,一直直走只要箱子不撞墙,那么你拐弯前的答案就可以累加到拐弯后的状态上

不难得到 d p [ i ] [ j ] [ 0 / 1 ] dp[i][j][0/1] 表示 ( i , j ) (i,j) 从左边或者上边过来的方案数

转移:
d p [ i ] [ j ] [ 0 ] = k = x j 1 d p [ i ] [ k ] [ 1 ] dp[i][j][0] = \sum_{k=x}^{j-1} dp[i][k][1]
d p [ i ] [ j ] [ 1 ] = k = y i 1 d p [ k ] [ j ] [ 0 ] dp[i][j][1] = \sum_{k=y}^{i-1} dp[k][j][0]

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

const ll N = 2010;
const ll mod = 1e9+7;

ll dp[N][N][2],sum[N][N][2];
ll sumr[N][N],sumc[N][N];

char str[N][N];

int main()
{
//  freopen("a.in","r",stdin);
  
  ll n = read(); ll m = read();
  
  if(n==1 && m==1){puts("1"); return 0;}
  
  for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) cin >> str[i][j];
  
  for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) sumr[i][j] = sumr[i][j-1] + (str[i][j] == 'R');
  for(ll j=1;j<=m;j++) for(ll i=1;i<=n;i++) sumc[i][j] = sumc[i-1][j] + (str[i][j] == 'R');
  
  for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++)
  {
    if(i==1) dp[i][j][0] = (sumr[i][m] <= (m-j));
    if(j==1) dp[i][j][1] = (sumc[n][j] <= (n-i));
    if(i!=1 && j!=1)
    {
      ll l = 1; ll r = j-1; ll ret = 0;
      while(l<=r)
      {
        ll mid = (l+r)>>1;
        if(sumr[i][m] - sumr[i][mid] <= m-j) ret = mid,r = mid - 1;
        else l = mid + 1;
      }
//      printf("(%d,%d) 0 : %d\n",i,j,ret);
      if(ret) dp[i][j][0] = (sum[i][j-1][1] - sum[i][ret-1][1] + mod) % mod;
      
      l = 1; r = i-1; ret = 0;
      while(l<=r)
      {
        ll mid = (l+r)>>1;
        if(sumc[n][j] - sumc[mid][j] <= n-i) ret = mid,r = mid - 1;
        else l = mid + 1;
      }
//      printf("(%d,%d) 1 : %d\n",i,j,ret);
      if(ret) dp[i][j][1] = (sum[i-1][j][0] - sum[ret-1][j][0] + mod) % mod;
    }
    sum[i][j][0] = (sum[i-1][j][0] + dp[i][j][0]) % mod;
    sum[i][j][1] = (sum[i][j-1][1] + dp[i][j][1]) % mod;
//    printf("(%d,%d) %d %d %d %d\n",i,j,dp[i][j][0],dp[i][j][1],sumr[i][m],sumc[n][j]);
  }
  return printf("%lld\n",(dp[n][m][0] + dp[n][m][1]) % mod),0;
}

/*

left dp[i][j][0] = sigma(dp[i][y to j-1][1]) [sumr[i][m] - sumr[i][y] <= m-j+1] 
up dp[i][j][1] = sigma(dp[x to i-1][j][0])

*/

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/102800268