码迷,mamicode.com
首页 > 其他好文 > 详细

【CF1247E】Rock Is Push(DP,二分)

时间:2019-10-27 23:11:32      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:队列   pre   using   eof   ++   范围   can   get   tin   

题意:有一个n*m的方格,每一格可能为空也可能有石头,要从(1,1)走到(n,m),每次可以往右或往下走

每次走的时候都会将自己面前的所有石头向移动方向推一格,如果碰到了边界就推不过去

问方案数模1e9+7

n,m<=2e3

思路:设dp[i][j][0/1]分别为当前走到(i,j),上一次从左/上走的合法方案数

合法的转移是行坐标或列坐标连续的一段,而且受障碍物个数和当前行/列号限制

写出式子之后可以发现决策范围对于i相同或者j相同是单调的,可以用队列维护,但显然二分更好写

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned int uint;
  5 typedef unsigned long long ull;
  6 typedef long double ld;
  7 typedef pair<int,int> PII;
  8 typedef pair<ll,ll> Pll;
  9 typedef vector<int> VI;
 10 typedef vector<PII> VII;
 11 //typedef pair<ll,ll>P;
 12 #define N  2010
 13 //#define M  200010
 14 #define INF 1e9
 15 #define fi first
 16 #define se second
 17 #define MP make_pair
 18 #define pb push_back
 19 #define pi acos(-1)
 20 #define mem(a,b) memset(a,b,sizeof(a))
 21 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
 22 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
 23 #define lowbit(x) x&(-x)
 24 #define Rand (rand()*(1<<16)+rand())
 25 #define id(x) ((x)<=B?(x):m-n/(x)+1)
 26 #define ls p<<1
 27 #define rs p<<1|1
 28 
 29 const ll MOD=1e9+7,inv2=(MOD+1)/2;
 30       double eps=1e-6;
 31       int dx[4]={-1,1,0,0};
 32       int dy[4]={0,0,-1,1};
 33 
 34 char ch[N];
 35 ll dp[N][N][2],s[N][N][2];
 36 int b[N][N];
 37 
 38 int read()
 39 {
 40    int v=0,f=1;
 41    char c=getchar();
 42    while(c<48||57<c) {if(c==-) f=-1; c=getchar();}
 43    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 44    return v*f;
 45 }
 46 
 47 int calcb(int x1,int y1,int x2,int y2)
 48 {
 49     return b[x2][y2]-b[x1-1][y2]-b[x2][y1-1]+b[x1-1][y1-1];
 50 }
 51 
 52 ll calc(int x1,int y1,int x2,int y2,int op)
 53 {
 54     ll res=s[x2][y2][op]-s[x1-1][y2][op]-s[x2][y1-1][op]+s[x1-1][y1-1][op];
 55     res=(res%MOD+MOD)%MOD;
 56     return res;
 57 }
 58 
 59 void add(ll &a,ll b)
 60 {
 61     a+=b;
 62     if(a>=MOD) a-=MOD;
 63     if(a<0) a+=MOD;
 64 }
 65 
 66 int main()
 67 {
 68     int n=read(),m=read();
 69     if(n==1&&m==1)
 70     {
 71         printf("1\n");
 72         return 0;
 73     }
 74     rep(i,1,n)
 75     {
 76         scanf("%s",ch+1);
 77         rep(j,1,m)
 78          if(ch[j]==R) b[i][j]=1;
 79     }
 80     rep(i,1,n)
 81      rep(j,1,m) b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+b[i][j];
 82     dp[1][1][0]=dp[1][1][1]=1;
 83     s[1][1][0]=s[1][1][1]=1;
 84     rep(len,3,n+m)
 85     {
 86         rep(i,1,len-1)
 87         {
 88             int j=len-i;
 89             if(i>n||j>m) continue;
 90             int l=1,r=j-1,last=j;
 91             while(l<=r)
 92             {
 93                 int mid=(l+r)>>1;
 94                 if(calcb(i,mid+1,i,m)<=m-j){last=mid; r=mid-1;}
 95                  else l=mid+1;
 96             }
 97             if(last<j) add(dp[i][j][0],calc(i,last,i,j-1,1));
 98             add(s[i][j][0],s[i-1][j][0]);
 99             add(s[i][j][0],s[i][j-1][0]);
100             add(s[i][j][0],-s[i-1][j-1][0]);
101             add(s[i][j][0],dp[i][j][0]);
102 
103             l=1,r=i-1,last=i;
104             while(l<=r)
105             {
106                 int mid=(l+r)>>1;
107                 if(calcb(mid+1,j,n,j)<=n-i){last=mid; r=mid-1;}
108                  else l=mid+1;
109             }
110             if(last<i) add(dp[i][j][1],calc(last,j,i-1,j,0));
111             add(s[i][j][1],s[i-1][j][1]);
112             add(s[i][j][1],s[i][j-1][1]);
113             add(s[i][j][1],-s[i-1][j-1][1]);
114             add(s[i][j][1],dp[i][j][1]);
115         }
116 
117     }
118     ll ans=(dp[n][m][0]+dp[n][m][1])%MOD;
119     printf("%I64d\n",ans);
120     return 0;
121 }

 

【CF1247E】Rock Is Push(DP,二分)

标签:队列   pre   using   eof   ++   范围   can   get   tin   

原文地址:https://www.cnblogs.com/myx12345/p/11749247.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!