• Good Bye 2020


    传送门

    咕了好久的博客...回来诈个尸...

    A. Bovine Dilemma

    高是固定的,唯一的差别在于底。
    由于 (n) 很小,所以两两枚举统计差值的不同个数即可。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 09:15:16
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        set<int> s;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (a[i] != a[j]) {
                    s.insert(abs(a[i] - a[j]));
                }
            }
        }
        cout << sz(s) << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    B. Last minute enhancements

    注意到 (x_i) 非递减。
    那么从后往前贪心来做就行。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 09:20:36
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        int n;
        cin >> n;
        vector<int> cnt(2 * n + 1);
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            --x;
            ++cnt[x];
        }
        int ans = 0;
        for (int i = 2 * n - 1; i >= 0; i--) {
            if (cnt[i]) {
                if (!cnt[i + 1]) {
                    ++cnt[i + 1], --cnt[i], ans += 2;
                    if (cnt[i] == 0) --ans;
                } else {
                    ++ans;
                }
            }
        }
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    C. Canine poetry

    题意:
    给定一个字符串,现在一次操作可以修改任意一个位置的字符。
    问最少修改多少次使得该串不存在长度大于1的回文串。

    思路:
    很有意思的一道题目。
    注意到满足一个长度大于1的回文串,必然满足存在长度等于2或者3的回文串。所以我们只需要考虑消除所有长度等于2或者3的回文串。
    考虑一个字符最多会影响左右各两个字符,而字符集大小为26,所以一定可以通过枚举找到一个与他们都不相等的字符。
    所以从前往后逐个击破即可。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 09:38:39
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        string s;
        cin >> s;
        int n = s.length();
        int ans = 0;
        for (int i = 1; i < n; i++) {
            if (s[i - 1] == s[i] || (i > 1 && s[i] == s[i - 2])) {
                ++ans;
                for (int j = 0; j < 26; j++) {
                    if (j != s[i - 1] - 'a' 
                        && (i - 2 < 0 || j != s[i - 2] - 'a')
                        && (i + 1 >= n || j != s[i + 1] - 'a')
                        && (i + 2 >= n || j != s[i + 2] - 'a')
                    ) {
                        s[i] = char(j + 'a');
                        break;
                    }
                }
            }
        }
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while (T--)
        run();
        return 0;
    }
    

    D. 13th Labour of Heracles

    题面较绕...不过稍微思考一下就可以发现,贪心来做就行。
    代码应该比较好懂。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 09:57:09
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        vector<int> d(n);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            --u, --v;
            ++d[u], ++d[v];
        }
        priority_queue<pii> que;
        ll ans = 0;
        for (int i = 0; i < n; i++) {
            que.push(MP(a[i], d[i] - 1));
            ans += a[i];
        }
        cout << ans;
        for (int i = 1; i < n - 1; i++) {
            while (!que.empty()) {
                pii cur = que.top(); que.pop();
                if (cur.se == 0) continue;
                ans += cur.fi;
                --cur.se;
                if (cur.se > 0) que.push(cur);
                break;
            }
            cout << ' ' << ans;
        }
        cout << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    E. Apollo versus Pan

    求和式子看似时间复杂度要爆炸,实际上我们可以利用二进制每位独立的性质,提前预处理来做。
    大概就是先预处理,然后 (O(n)) 消掉后面的两个和式得到 (displaystyle f(j)=sum_{k=1}^n(x_j|x_k))
    之后又通过预处理,(O(n)) 求得答案。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 10:09:58
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, MOD = 1e9 + 7;
    void run() {
        int n;
        cin >> n;
        vector<ll> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        vector<int> has(60);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 60; j++) if (a[i] >> j & 1) {
                ++has[j];
            }
        }
        vector<int> f(n);
        for (int j = 0; j < n; j++) {
            int res = 0;
            for (int bit = 0; bit < 60; bit++) {
                if (a[j] >> bit & 1) {
                    res = (res + (1ll << bit) % MOD * n % MOD) % MOD;
                } else {
                    res = (res + (1ll << bit) % MOD * has[bit] % MOD) % MOD;
                }
            }
            f[j] = res;
        }
        vector<int> g(60);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 60; j++) {
                if (a[i] >> j & 1) {
                    g[j] = (g[j] + f[i]) % MOD;
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 60; j++) if (a[i] >> j & 1) {
                ans = (ans + (1ll << j) % MOD * g[j] % MOD) % MOD;
            }
        }
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    F. Euclid's nightmare

    题意:
    给出 (n)(m) 维01向量,每一个向量至多两个 (1)
    问多少种不同的情况能被这 (n) 个向量表出。
    要求输出能表示出这些情况的一个最小向量集,这里的最小首先要求集合大小最小,其次向量按照输入顺序的字典序最小。

    思路:
    显然,我们可以大致将最终的结果分为两类:自由位、与其它位有联系的位。

    接下来考虑怎么确定自由位:假设一个向量只有一个自由位,那么可以直接确定;假设一个向量有两个自由位,并且其中之一为自由位,那么这一位也变为自由位。
    那我们考虑按顺序进行模拟,但可能出现这种情况:第 (x) 位为自由位,现有一个向量第 (y,z) 位为1,之后有一个向量第 (x,y) 位为1,那么 (z) 也“自动”变为了自由位。
    所以我们可以考虑用并查集维护连通块来实现上述过程。
    注意一个集合中只需要一个原本就是自由位的位即可,这样能满足集合大小最小。

    确定与其它位有联系的位的话,按照上述思路自然而然地想到维护连通块。不过计算答案时有差异:假设连通块大小为 (x),那么对答案的贡献即为 (2^{x-1})。因为我们只要把某两个缩成一个点,将他们看作一个自由位,最后就会有 (x-1) 个自由位。

    Code
    // Author : heyuhhh
    // Created Time : 2020/12/31 10:38:31
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, MOD = 1e9 + 7;
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if (b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    void run() {
        int n, m;
        cin >> n >> m;
        vector<int> ans;
        int res = 1;
        vector<int> f(m);
        vector<int> siz(m, 1);
        vector<int> has(m);
        iota(all(f), 0);
    
        auto find = [&] (int x) {
            while (x != f[x]) {
                int t = f[x];
                f[x] = f[f[x]];
                x = t;
            }
            return x;
        };
        auto Union = [&] (int x, int y) {
            x = find(x), y = find(y);
            if (x != y) {
                if (has[x] > has[y]) {
                    swap(x, y);
                }
                if (has[x] == 0) {
                    f[x] = y;
                    siz[y] += siz[x];
                    return true;
                }
            }
            return false;
        };
        
        for (int i = 0; i < n; i++) {
            int k;
            cin >> k;
            if (k == 1) {
                int x;
                cin >> x;
                --x;
                int fx = find(x);
                if (!has[fx]) {
                    has[fx] = 1;
                    ans.emplace_back(i);
                }
            } else {
                int x, y;
                cin >> x >> y;
                --x, --y;
                if (Union(x, y)) {
                    ans.emplace_back(i);
                }
            }
        }
    
        sort(all(ans));
        for (int i = 0; i < m; i++) if (f[i] == i) {
            if (has[i]) res = 1ll * res * qpow(2, siz[i]) % MOD;
            else res = 1ll * res * qpow(2, siz[i] - 1) % MOD;
        }
        cout << res << ' ' << sz(ans) << '
    ';
        for (auto it : ans) {
            cout << it + 1 << ' ';
        }
        cout << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    G. Song of the Sirens

    题意:
    给定 (s_0,t) 两个字符串,定义 (s_i=s_{i-1}t_{i-1}s_{i-1})
    之后会有 (q) 组询问,每组询问给出 (id s)
    现在回答 (s_{id}) 里面包含多少 (s)
    保证所有的 (s) 长度之和不超过 (10^6)

    思路:
    这个题和济南的L题简直不能太像,济南就是因为两个bug没有出L呜呜呜(错失金牌)
    一开始还想利用上 (s_0leq 100) 这个条件,貌似最后根本用不上...
    对于每一组询问,我们只需要找到最小的 (k),使得 (|s_k|geq |s|)。这一段我们暴力计算答案。
    之后因为是直接拼接,那么我们只需要利用 (s_k) 的头和尾。提前预处理所有的三元组 ((x,y,i)),分别表示尾巴 (x),头部 (y),满足 (x+y+1=|s|) 并且对应的与 (s) 相等,并且 (s[x] - 'a'= i)
    我们记 (f(i)) 表示满足上述条件的三元组个数,(0leq i<26)。这里可以hash或者kmp之类的计算。

    接下来考虑计算答案。因为询问的 (id) 可能很大,虽然每一个位置的贡献我们很容易求,为2的若干次幂,但不可能一位一位去求。
    思考后其实可以发现,我们只需要对每一类字符单独统计贡献即可,结合“每一类字符两两相邻的位置差不变”这一性质。所以对每一类字符最后乘以或者除以一个2的若干次幂就快速求得答案啦。
    细节见代码吧,感觉类似预处理的思想很常见,一般的hash其实就类似于这样。

    Code
    // Author : heyuhhh
    // Created Time : 2021/01/05 11:39:55
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e6 + 5, MOD = 1e9 + 7, INV = (MOD + 1) / 2;
    
    inline int add(int x, int y) {
        return x + y >= MOD ? x + y - MOD : x + y;
    }
    inline int dec(int x, int y) {
        return x - y < 0 ? x - y + MOD : x - y;
    }
    inline int mul(int x, int y) {
        return 1ll * x * y % MOD;
    }
    
    int pow2[N], inv2[N];
    void init() {
        pow2[0] = inv2[0] = 1;
        for (int i = 1; i < N; i++) {
            pow2[i] = mul(pow2[i - 1], 2);
            inv2[i] = mul(inv2[i - 1], INV);
        }
    }
    
    typedef unsigned long long ull;
    template <unsigned mod, unsigned base>
    struct rolling_hash {
        unsigned int pg[N], val[N]; // val:1,2...n
        rolling_hash() {
            pg[0] = 1;
            for(int i = 1; i < N; i++) pg[i] = 1ull * pg[i - 1] * base % mod;
            val[0] = 0;
        }
        void build(const char *str) {
            for(int i = 0; str[i]; i++) {
                val[i + 1] = (str[i] + 1ull * val[i] * base) % mod;
            }
        }
        unsigned int operator() (int l, int r) {
            ++r; // 
            return (val[r] - 1ull * val[l] * pg[r - l] % mod + mod) % mod;
        }
    };
    struct dm_hasher {
        //str:0,1...len-1
        rolling_hash<997137961, 753> h1;
        rolling_hash<1003911991, 467> h2;
        void build(const char *str) {
            h1.build(str); h2.build(str);
        }
        ull operator() (int l, int r) {
            return ull(h1(l, r)) << 32 | h2(l, r);
        }
    }hasher, hasher2;
    
    void run() {
        int n, q;
        cin >> n >> q;
        string s0, t;
        cin >> s0 >> t;
        vector<vector<int>> pos(26);
        for (int i = 0; i < n; i++) {
            pos[t[i] - 'a'].emplace_back(i);
        }
    
        vector<int> c(n);
        vector<int> last(26);
        for (int i = 0; i < 26; i++) {
            for (int j = sz(pos[i]) - 1; j >= 0; j--) {
                if (j == sz(pos[i]) - 1) {
                    c[pos[i][j]] = 1;
                    last[i] = pos[i][j];
                } else {
                    c[pos[i][j]] = add(c[pos[i][j + 1]], pow2[last[i] - pos[i][j]]);
                }
            }
        }
        while (q--) {
            int id;
            string s;
            cin >> id >> s;
            int len = s.length();
            int k;
            string res = s0;
            int ans = 0;
            for (int i = 0; i <= id; i++) {
                if (res.length() >= len) {
                    k = i;
                    break;
                }
                if (i < id) res += t[i] + res;
            }
            if (res.length() < len) {
                cout << 0 << '
    ';
                continue;
            }
            hasher.build(res.c_str());
            hasher2.build(s.c_str());
            ull val = hasher2(0, len - 1);
            int resLen = res.length();
            for (int i = 0; i + len - 1 < resLen; i++) {
                int j = i + len - 1;
                if (hasher(i, j) == val) {
                    ++ans;
                }
            }
            ans = mul(ans, pow2[id - k]);
            vector<int> f(26);
            for (int j = 1; j < len; j++) {
                if (hasher(resLen - j, resLen - 1) == hasher2(0, j - 1)
                    && hasher(0, len - j - 2) == hasher2(j + 1, len - 1)
                    ) {
                        ++f[s[j] - 'a'];
                    }
            }
            if (hasher(0, len - 2) == hasher2(1, len - 1)) {
                ++f[s[0] - 'a'];
            }
            // add t[k]....t[id - 1]
            for (int i = 0; i < 26; i++) if (f[i]) {
                int lAt = lower_bound(all(pos[i]), k) - pos[i].begin();
                int rAt = lower_bound(all(pos[i]), id) - pos[i].begin() - 1;
                int res = 0;
                if (lAt == sz(pos[i])) continue;
                if (rAt == sz(pos[i]) - 1) {
                    res = mul(f[i], mul(c[pos[i][lAt]], pow2[id - 1 - last[i]]));
                } else {
                    int tmp = dec(c[pos[i][lAt]], c[pos[i][rAt + 1]]);
                    res = mul(f[i], mul(tmp, inv2[last[i] - id + 1]));
                }
                ans = add(ans, res);
            }
            cout << ans << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        run();
        return 0;
    }
    
  • 相关阅读:
    优化 Markdown 在 Notepad++ 中的使用体验
    error C1128: 节数超过对象文件格式限制: 请使用 /bigobj 进行编译
    Git: 代码冲突常见解决方法
    fatal error c1001 编译器中发生内部错误 OpenMesh6.3
    error C2448 函数样式初始值设定项类似函数定义
    VS Code 配置Python
    15分钟掌握 Git
    notepad++快捷键
    【Python笔记】第4章 操作列表
    【MySQL】MySQL按中文排序
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/14236867.html
Copyright © 2020-2023  润新知