2023.6.19 每日一题

原题链接

A: Educational Codeforces Round 103 (Rated for Div. 2) - E

B: Codeforces Round 744 (Div. 3) - F

A. Pattern Matching - 2300

题目大意

给定 \(n\) 个模式串和 \(m\) 个匹配串,模式串中可能含有通配符_,现在需要对模式串重新排列,使得匹配上每一个匹配串的第一个模式串是第 \(t_i\) 个 ,如果可以得到满足,那么输出排序结果。

解题思路

我们需要匹配到的第一个模式串恰好排第 \(t_i\) 位,那么在所有与这个匹配串匹配的串中,这个串需要放最前面,那么需要考虑跑一个拓扑排序,同时为了降低复杂度,我们可以从匹配串入手,往模式串连边。因为这样每个匹配串最多建立 \(2^4\) 条边,不会TLE。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 2e5 + 10;
const int MOD = 1e9 + 7;

vector<int> v[N];
map<string, int> mp;
vector<int> path;
bool vis[N];
bool ever[N];

void dfs(int u) {
    if (vis[u]) {
        cout << "NO" << endl;
        exit(0);
    }
    if (ever[u]) return;
    vis[u] = ever[u] = true;
    for (auto i : v[u]) {
        dfs(i);
    }
    vis[u] = false;
    path.push_back(u);
}

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= n; ++i) {
        string s;
        cin >> s;
        mp[s] = i;
    }
    bool flag = true;
    for (int i = 1; i <= m; ++i) {
        string s;
        int x;
        cin >> s >> x;
        flag = true;
        for (int j = 0; j < (1 << k); ++j) {
            string t = s;
            for (int l = 0; l < k; ++l) {
                if ((j >> l) & 1) {
                    t[l] = '_';
                }
            }
            if (mp.contains(t)) {
                if (mp[t] == x) {
                    flag = false;
                } else {
                    v[mp[t]].push_back(x);
                }
            }
        }
        if (flag) {
            cout << "NO" << endl;
            return;
        }
    }
    for (int i = 1; i <= n; ++i) {
        dfs(i);
    }
    cout << "YES" << endl;
    for (int i = 0; i < n; ++i) {
        cout << path[i] << ' ';
    }
}

signed main() {
    ios;
    int T = 1;
//    cin >> T;
    while (T--) {
        solve();
    }
}

B. Array Stabilization (AND version) - 1700

题目大意

给定一个下标从 \(0\) 开始的数组,反复做如下操作:

  1. 将数组向右移动 \(d\) 位得到 \(b\) 数组。
  2. 将数组每一位替换成 \(a_i\ \&\ b_i\)

直到数组不再发生变化为止,问如果能使得最后的数组全为 \(0\),一共经过了多少步。

解题思路

我们使用一个set存储 \(0\) 的位置模拟这个过程。每次遍历的时候,记录新数组与原来数组相比,\(0\) 的数量改变了多少,同时对我们的位置set进行更新即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 1e6 + 10;
const int MOD = 1e9 + 7;

int a[N];
set<int> st;

void solve() {
    int n, d;
    st.clear();
    LL res = 0;
    cin >> n >> d;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
        if (!a[i]) {
            cnt++;
            if (a[(i + d) % n]) {
                st.insert(i);
            }
        }
    }
    while (cnt < n) {
        set<int> tmp1, tmp2;
        res++;
        if (st.empty()) {
            cout << -1 << endl;
            return;
        }
        for (int i : st) {
            cnt++;
            tmp1.insert(i);
            a[(i + d) % n] = 0;
            if (a[(i + (d << 1)) % n]) {
                tmp2.insert((i + d) % n);
            }
        }
        for (int i : tmp1) {
            st.erase(i);
        }
        for (int i : tmp2) {
            st.insert(i);
        }
    }
    cout << res << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}
posted @ 2023-06-19 21:56  叁纔  阅读(19)  评论(0编辑  收藏  举报