2019牛客多校第一场

2019牛客多校第一场

E:ABBA(贪心+DP)

  • 题意:就是有\(n\)个"AB",\(m\)个"BA",问能结合成多少个序列.这个要求是AB和BA的顺序不变,即A和B的相对位置不变.我们要讨论一下什么才是合法的状态.

  • 贪心:
    • 假设只有\(n​\)个AB,合法情况是每个B前面要有\(1 ...n​\)个A
    • 假设除了有AB,还有\(m\)个BA,那每个B前面可以有超过\(n\)个A,但是第一个B前面还是要有\(1...n\)个A.否则就会使BA类型的某个B后面没A.
    • B与后面的A可以构成BA,相当于抵消了一个A,那下一个B前面就只需要有\(1...n​\)未被抵消的A.
    • 所以A-B小于等于\(n\)是合法的.当A-B等于\(n\),意味着最后一个只能是A,因为如果最后一个是B,那B前面就有\(n+1\)个未被抵消的A.
    • A前面有多少个B也是同理.
  • DP

    • \(dp[i][j]\)\(i\)代表A的个数,\(j\)代表B的个数.\(dp\)值代表合法方案.

    • 初始化,按照上述每个A前面有\(1...m\)个B是合法,每个B前面有\(1...n\)个A是合法

    • \(dp[i][0]=dp[0][j]=1\)

    • 不考虑那么多,可以得出
      \[ dp[i][j]=dp[i-1][j]+dp[i][j-1] \]

    • 但是要排除非法的情况

      • \(0\leq j-i\leq m\)\(0\leq i-j \leq n\) 是合法情况
      • 注意\(=m\)\(=n\)\(=0\)的情况
  • 还是想说,浩哥天下第一

  • 代码

    #include <bits/stdc++.h>
    
    #define ll long long
    using namespace std;
    const ll mod = 1e9 + 7;
    const ll N = 1e5 + 10;
    ll dp[2010][2010];
    
    int main() {
        ll n, m;
        while (scanf("%lld%lld", &n, &m) != EOF) {
            ll cnt = (n + m);
            for (int i = 0; i <= cnt; i++)
                for (int j = 0; j <= cnt; j++)
                    dp[i][j] = 0;
            for (ll i = 0; i <= cnt; i++) {
                dp[i][0] = dp[0][i] = 1;
            }
            for (ll i = 1; i <= cnt; i++) {
                for (ll j = 1; j <= cnt; j++) {
                    if (i == j) {
                        if (n)
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod;
                        if (m)
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % mod;
                    } else if (j > i) {
                        if (j - i < m)
                            dp[i][j] = ((dp[i][j] + dp[i - 1][j]) % mod + dp[i][j - 1]) % mod;
                        else if (j - i == m)
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod;
                    } else if (i > j) {
                        if (i - j < n)
                            dp[i][j] = ((dp[i][j] + dp[i - 1][j]) % mod + dp[i][j - 1]) % mod;
                        if (i - j == n)
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % mod;
                    }
                    //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
                }
            }
            printf("%lld\n", dp[cnt][cnt] % mod);
        }
    
        return 0;
    

猜你喜欢

转载自www.cnblogs.com/smallocean/p/11209720.html