CF1225E説明ロックプッシュです

私は、この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つの、そしてある状態遷移式です。

キャプチャ.PNG

上記のように、我々は黄色でグリッドを想定\((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;
}

おすすめ

転載: www.cnblogs.com/lost-in-tianyi/p/11762166.html