T1:复合逻辑表达式

本题难度中等,线性 \(dp\) 问题。根据最后一个运算递推:如果是 AND,需要两边都是 true;如果是 OR,只需任意一个是 true

S[i] = 'AND'
y[i-1]=T 且 x[i]=T: y[i] = T
y[i-1]=T 且 x[i]=F: y[i] = F
y[i-1]=F 且 x[i]=T: y[i] = F
y[i-1]=F 且 x[i]=F: y[i] = F

y[i]=T 的方案数等于 y[i-1]=T 的方案数
y[i]=F 的方案数等于 y[i-1]=F 的方案数 $\times 2 \ + $ y[i-1]=T 的方案数等于 y[i-1]=T 的方案数

dp[i][0] 表示 y[i]=F 的方案数,dp[i][1] 表示 y[i]=T 的方案数
转移方程:

s[i]='AND' 时:
\( dp[i][0] = dp[i-1][0]*2 + dp[i-1][1] \)
\( dp[i][1] = dp[i-1][1] \)

s[i]='OR' 时:

y[i-1]=F 或 x[i]=F: y[i] = F
y[i-1]=T 或 x[i]=F: y[i] = T
y[i-1]=F 或 x[i]=T: y[i] = T
y[i-1]=T 或 x[i]=T: y[i] = T

\( dp[i][0] = dp[i-1][0] \)
\( dp[i][1] = dp[i-1][1]*2 + dp[i-1][0] \)

答案是 \(dp[n][1]\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

ll dp[65][2];

int main() {
    int n;
    cin >> n;
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    
    dp[0][0] = dp[0][1] = 1;
    rep(i, n) {
        if (s[i] == "AND") {
            dp[i+1][0] = dp[i][0]*2 + dp[i][1];
            dp[i+1][1] = dp[i][1];
        }
        else {
            dp[i+1][0] = dp[i][0];
            dp[i+1][1] = dp[i][1]*2 + dp[i][0];
        }
    }
    
    cout << dp[n][1] << '\n';
    
    return 0;
}

T2:反转字符串排序

本题难度中等,也是线性dp问题,需要加 \(1\) 维记录结尾单词有没有反转。

状态表示:

dp[i][0] 表示第 \(i\) 个字符串不反转,令 \(s_i\) 有序的最小代价
dp[i][1] 表示第 \(i\) 个字符串反转,令 \(s_i\) 有序的最小代价

初始化:

\( dp[1][0] = 0; \ dp[1][1] = c_1 \)

转移方程:

如果 \(s_{i-1}\) 不转 \(\leqslant s_i\) 不转:

\( dp[i][0] = \min(dp[i][0], dp[i-1][0]) \)

如果 \(s_{i-1}\)\(\leqslant s_i\) 不转:

\( dp[i][0] = \min(dp[i][0], dp[i-1][1]) \)

如果 \(s_{i-1}\) 不转 \(\leqslant s_i\) 转:

\( dp[i][1] = \min(dp[i][1], dp[i-1][0] + c_i) \)

如果 \(s_{i-1}\)\(\leqslant s_i\) 转:

\( dp[i][1] = \min(dp[i][1], dp[i-1][1] + c_i) \)

最后的答案是 \(\min(dp[n][0], dp[n][1])\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

inline void chmin(ll& x, ll y) { if (x > y) x = y; }

int main() {
    int n;
    cin >> n;
    
    vector<int> c(n);
    rep(i, n) cin >> c[i];
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    vector<string> r = s;
    rep(i, n) {
        reverse(r[i].begin(), r[i].end());
    }
    
    const ll INF = 1e18;
    vector<vector<ll>> dp(n+1, vector<ll>(2, INF));
    dp[0][0] = 0;
    dp[0][1] = c[0];
    for (int i = 1; i < n; ++i) {
        if (s[i-1] <= s[i]) chmin(dp[i][0], dp[i-1][0]);
        if (r[i-1] <= s[i]) chmin(dp[i][0], dp[i-1][1]);
        if (s[i-1] <= r[i]) chmin(dp[i][1], dp[i-1][0]+c[i]);
        if (r[i-1] <= r[i]) chmin(dp[i][1], dp[i-1][1]+c[i]);
    }
    
    ll ans = min(dp[n-1][0], dp[n-1][1]);
    if (ans == INF) ans = -1;
    cout << ans << '\n';
    
    return 0;
}