标签:队列 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 }
标签:队列 pre using eof ++ 范围 can get tin
原文地址:https://www.cnblogs.com/myx12345/p/11749247.html