私は、このWWWを期待していなかったときに遊んCF DPは実際にはかなり賢いです
これは、質問DP(ナンセンスです
我々が行ったと仮定し\((i、j)は\ ) 我々は唯一の私たちが岩の上に残されているすべての(つまり、その後、右/下に移動することができるので、位置\(\ {(I、J iがnを<|) \スペース|| \空間J <M \} \) の石)に関係なく、そこにプッシュし、私はメロンを持っていません(いくつかの写真少しプッシュを描くことができ、それは)非常に明白である、それは問題ありません後に効果であり、利用可能dpが解決しました。
一緒にカウントは非常に良いではありません、我々は右へとDPダウンそれらを別々に考えることができます。
だから我々は、配列を使用することができます\(RS、DSを\)のみこれらの石がするので、位置の右にある番号の下石や岩の数を記録するために、((i、j)は\ \ ) 転移の状態を
提供される二次元アレイ状態\(R&LT、D \)を表し、\((i、j)は\ ) の右隣に位置する(\(R&LT \) )またはダウン(\(D \)目標に到達するために移動します)位置\((N、M)\ ) 定義から利用可能なプログラムの総数\(R&LT [N-] [M] = D [N-] [M] = 1 \) 。
状態遷移方程式:wの混乱への鍵
それはに分割されているので、なぜこの質問独創的な理由は、まず、\(R、Dの\) DPするために2つの、そしてある状態遷移式です。
上記のように、我々は黄色でグリッドを想定\((I、J)\) 、石の青い円、石点線軌道。そして、入手しやすい\(DS [I] [J] = 1 \)(\ (RS \)上記参照忘れ定義します)。次のステップで、我々はダウン行かなければならないので、我々は、連続歩行選択することができますので、\(1 \)ステップ、\(2 \)まで...手順を(NI-DS [i]を\ \ [J]) のステップまで、このとき、ちょうど石の下には、すべての並ぶ壁に一つずつプッシュされます。このように、すなわち、状態遷移方程式
\ [D [i]は[J] = \ sum_ {k = 1} ^ {NI-DS [I] [J]} R [I] [J + K] \]
\ [R [I] [J] = \ sum_ {k = 1} ^ {MI-RS [I] [J]} D [I + K] [J] \]
(先に疑いのソリューション:ここのために\(R \)配列の合計ではなく\(Dの\)配列の総和が、我々は継続的にダウンして行くことである理由\(k個の\を)次のステップはそう、右にする必要があります後ここで使用される\(R&LT \) 、およびその逆)
非常に偶然、まだ考えて(あるいはそれが弱すぎるネストQAQです
もちろん、列挙型の\(R [i]は[J + K]、D [I + K] [j]は\) 確かにそうここに私達は接頭辞を使用して保存し、タイムアウトになります。
それでもこんにゃくコードコメントWWWを見ることができますdalaoのポイントを理解していなかった場合は〜
コード:
#include<bits/stdc++.h>
using namespace std;
long long n , m , r[2100][2100] , d[2100][2100] , ds[2100][2100] , rs[2100][2100];
long long sumr[2100][2100] , sumd[2100][2100];
const int mod = 1e9 + 7;
char s[2100];
//d:down r:right
int main()
{
scanf("%d%d" , &n , &m);
for(register int i = 1 ; i <= n ; i++ )
{
scanf("%s" , s + 1);
for(register int j = 1 ; j <= m ; j++ )
{
if(s[j] == 'R') rs[i][j] = 1 , ds[i][j] = 1;
}
}
if(n == 1 && m == 1)
{
cout << (rs[1][1] ^ 1);
return 0;
}
for(register int i = n ; i >= 1 ; i-- )
{
for(register int j = m ; j >= 1 ; j-- )
{
ds[i][j] += ds[i][j + 1];
rs[i][j] += rs[i + 1][j];
}
}
r[n][m] = d[n][m] = sumd[n][m] = sumr[n][m] = 1;
for(register int i = n ; i >= 1 ; i-- )
{
for(register int j = m ; j >= 1 ; j-- )
{
if(i == n && j == m) continue;
r[i][j] = (sumd[i][j + 1] - sumd[i][m - ds[i][j + 1] + 1]) % mod;
d[i][j] = (sumr[i + 1][j] - sumr[n - rs[i + 1][j] + 1][j]) % mod;
//+1 : sum±Ø±¸ n - ds : ¼´i + (n - i - ds)»¯¼òºóµÄ½á¹û.
//d[i][j] : ´Ë²½ÏòÏÂ×ߺóÓм¸ÖÖ¿ÉÄܵ½(n , m); r[i][j] : ÏòÓÒ×ß
//ds[i][j] : (i , j) ÏÂÃæÓжàÉÙ¿éʯͷ , rs[i][j] : (i , j)ÓÒ±ß
//d[i][j] = sum(r[n - i - 1...ds[i][j + 1] + i][j]) , rͬÀí
//ÒâΪÔÚÏÂÒ»¸öÏòÓÒ×ß֮ǰ£¬Ñ¡ÔñÏòÏÂ×ß1...ds[i][j + 1]´Î£¬È»ºóÔÙÏòÏÂ×ߵķ½°¸ÊýÖ®ºÍ¡£
//ÇÉÃîwww
sumr[i][j] = (sumr[i + 1][j] + r[i][j]) % mod;
sumd[i][j] = (sumd[i][j + 1] + d[i][j]) % mod;
}
}
/*for(register int i = 1 ; i <= n ; i++ )
{
for(register int j = 1 ; j <= m ; j++ )
{
cout << d[i][j] << ' ';
}
cout << endl;
}
cout << endl;
for(register int i = 1 ; i <= n ; i++ )
{
for(register int j = 1 ; j <= m ; j++ )
{
cout << r[i][j] << ' ';
}
cout << endl;
}*/
// cerr << r[1][1] << " " << d[1][1] << endl;
cout << ((r[1][1] + d[1][1]) % mod + mod) % mod;
return 0;
}