CF1225E Rock Is Push (計數)
阿新 • • 發佈:2021-07-27
觀察性質計數題orz小賀
考場上跟榜才切
我們只能往下和往右走,那麼只有連續的往下和往右可能會造成不合法的情況!如果當前這一步是向右,那麼只有它前面連續的一段向右可能影響到它。
考慮把連續的向右/下一起處理,使得只有右和下之間相互轉移。
假設向下走到達當前點\((i,j)\),接下來向右走若干段,那麼能走的格數只和它右面的箱子數有關。而且能到達的位置是連續的一段
向右走到達當前點同理
點數是\(O(n^{2})\)的,每個方向可能轉移到\(O(n)\)個位置,暴力轉移是\(O(n^{3})\)的。因此需要字首和打差分優化,時間優化成\(O(n^{2})\)
#include <cstdio> #include <cstring> #include <algorithm> #define ull unsigned long long #define ll long long #define dd long double using namespace std; const int N1=2e3+5, p=1e9+7; template <typename _T> void read(_T &ret) { ret=0; _T fh=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); } ret=ret*fh; } int n,m; char str[N1][N1]; int a[N1][N1]; int qa(int ax,int ay,int bx,int by) { return a[bx][by]-a[ax-1][by]-a[bx][ay-1]+a[ax-1][ay-1]; } ll f[N1][N1][2],g[N1][N1][2],ysum[N1]; int main() { // freopen("a.in","r",stdin); // freopen("e0.out","w",stdout); read(n); read(m); if(n==1&&m==1){ puts("1"); return 0; } for(int i=1;i<=n;i++) scanf("%s",str[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]; a[i][j]+=(str[i][j]=='R'); } g[1][1][0]=1; g[1][2][0]=p-1; g[1][1][1]=1; g[2][1][1]=p-1; for(int i=1;i<=n;i++) { //1->0 for(int j=1;j<=m;j++) { (ysum[j]+=g[i][j][1])%=p; f[i][j][1]=ysum[j]; if(j==m) continue; int r=m-qa(i,j+1,i,m); (g[i][j+1][0]+=f[i][j][1])%=p; (g[i][r+1][0]+=-f[i][j][1]+p)%=p; } //0->1 ll xsum=0; for(int j=1;j<=m;j++) { (xsum+=g[i][j][0])%=p; f[i][j][0]=xsum; if(i==n) continue; int r=n-qa(i+1,j,n,j); (g[i+1][j][1]+=f[i][j][0])%=p; (g[r+1][j][1]+=-f[i][j][0]+p)%=p; } } // for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=m;j++) printf("%d ",a[i][j]); // puts(""); // for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=m;j++) printf("%lld ",f[i][j][0]); // puts(""); // for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=m;j++) printf("%lld ",f[i][j][1]); // puts(""); ll ans=(f[n][m][0]+f[n][m][1])%p; printf("%lld\n",ans); return 0; } `