zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 71 (Rated for Div. 2)

    传送门

    A.There Are Two Types Of Burgers

    签到。

    B.Square Filling

    签到

    C.Gas Pipeline

    每个位置只有“高、低”两种状态,所以直接根据条件来(dp)即可。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
    ll n, a, b;
    int T;
    char s[N];
    ll dp[N][2];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n >> a >> b;
            cin >> s;
            for(int i = 0; i <= n; i++) dp[i][0] = dp[i][1] = INF;
            dp[0][0] = b;
            for(int i = 1; i <= n; i++) {
                if(s[i - 1] == '1' || s[i] == '1') dp[i][1] = min(dp[i - 1][0] + 2 * (a + b), dp[i - 1][1] + a + 2 * b);
                else {
                    dp[i][0] = min(dp[i - 1][1] + 2 * a + b, dp[i - 1][0] + a + b);
                    dp[i][1] = min(dp[i - 1][1] + a + 2 * b, dp[i - 1][0] + 2 * (a + b));
                }
            }
            cout << dp[n][0] << '
    ';
        }
        return 0;
    }
    
    ### D.Number Of Permutations

    题意:
    给出(n)个二元组((a_i,b_i)),定义一个坏的序列为:序列中按第一关键字或者按第二关键字是非递减的。
    相反,好的序列的定义就与之相反。
    现在问有多少种打乱方式,能够得到好的序列。

    思路:

    • 考虑直接来求,发现过于复杂。
    • 所以考虑利用容斥的思想来做,先分别求出按第一关键字、第二关键字非递减的方案数,最后求出同时非递减的方案数,加加减减即可。
    • 同时非递减这种情况怎么处理呢?
    • 观察可以发现此时(a_i,b_i)分别非递减,所以我们就暴力扫一遍找共同部分就行了。
    • 那一个非递减,另一个不是呢?这种我们上面会计算到,此时答案为1,包含在上面计算中了。

    注意还有特殊情况的判断:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define INF 0x3f3f3f3f3f3f3f3f
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 3e5 + 5, MOD = 998244353;
    int n;
    pii p[N];
    ll fac[N];
    ll gao1() {
        ll res = 1;
        for(int i = 1, j; i <= n; i = j) {
            for(j = i; j <= n + 1; j++) {
                if(p[i].fi != p[j].fi) break;
            }
            int cnt = 1;
            for(int k = i + 1; k < j; k++) {
                if(p[k].se == p[k - 1].se) ++cnt;
                else {
                    res = res * fac[cnt] % MOD;
                    cnt = 1;
                }
            }
            res = res * fac[cnt] % MOD;
        }
        return res;
    }
    ll gao2() {
        ll res = 1;
        for(int i = 1, j; i <= n; i = j) {
            for(j = i; j <= n + 1; j++) {
                if(p[i].se != p[j].se) break;
            }
            int cnt = 1;
            for(int k = i + 1; k < j; k++) {
                if(p[k].fi == p[k - 1].fi) ++cnt;
                else {
                    res = res * fac[cnt] % MOD;
                    cnt = 1;
                }
            }
            res = res * fac[cnt] % MOD;
        }
        return res;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        for(int i = 1; i <= n; i++) {
            cin >> p[i].fi >> p[i].se;
        }
        sort(p + 1, p + n + 1);
        fac[0] = 1;
        for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % MOD;
        ll ans = fac[n];
        ll sum1 = 1, sum2 = 1;
        for(int i = 1, j; i <= n; i = j) {
            for(j = i; j <= n + 1; j++) {
                if(p[i].fi != p[j].fi) break;
            }
            sum1 = sum1 * fac[j - i] % MOD;
        }
        sort(p + 1, p + n + 1, [&](pii A, pii B) {
            return A.se < B.se;
        });
        for(int i = 1, j; i <= n; i = j) {
            for(j = i; j <= n + 1; j++) {
                if(p[i].se != p[j].se) break;
            }
            sum2 = sum2 * fac[j - i] % MOD;
        }
        ans -= sum1 + sum2;
        ans %= MOD; if(ans < 0) ans += MOD;
        bool f = 1;
        for(int i = 2; i <= n; i++) {
            if(p[i].fi < p[i - 1].fi) f = 0;
        }
        if(f) ans += gao1();
        else {
            f = 1;
            sort(p + 1, p + n + 1);
            for(int i = 2; i <= n; i++) {
                if(p[i].se < p[i - 1].se) f = 0;
            }
            if(f) ans += gao2();
        }
        cout << ans % MOD;
        return 0;
    }
    

    E. XOR Guessing

    题意:
    交互题。
    先有一个数大小不超过(2^{14}-1),给你两次机会,每次询问100个数,对方会告诉你这个数与从100个中随机一个数的异或值。注意所有询问的数都不能重复。
    最后输出此答案。

    思路:
    设答案为(ans)

    • 如果二进制一位全都是1,那么此时询问是不是很容易知道(ans)
    • 因为不能有重复,并且结合题目,我们就一次询问出一半的情况即可。
    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int N = 105;
    int a[N], b[N];
    int main() {
        //ios::sync_with_stdio(false); cin.tie(0);
        int now = 0;
        for(int i = 7; i <= 13; i++) {
            now += (1 << i);
        }
        for(int i = 1; i <= 100; i++) a[i] = i + now;
        now = 0;
        for(int i = 0; i <= 6; i++) {
            now += (1 << i);
        }
        int cnt = 0;
        for(int s = 0; s < 1 << 7; s++) {
            b[++cnt] = (s << 7) + now;
            if(cnt == 100) break;
        }
        int x, y;
        cout << "? ";
        for(int i = 1; i <= 100; i++) cout << a[i] << ' ';
        cout << '
    ';
        cin >> x;
        fflush(stdout);
        cout << "? ";
        for(int i = 1; i <= 100; i++) cout << b[i] << ' ';
        cout << '
    ';
        cin >> y;
        int ans = 0;
        for(int i = 7; i < 14; i++) {
            if(x >> i & 1) {}
            else ans += (1 << i);
        }
        for(int i = 0; i < 7; i++) {
            if(y >> i & 1) {}
            else ans += (1 << i);
        }
        cout << '!' << ' ' << ans;
        return 0;
    }
    

    F.F. Remainder Problem

    题意:
    现在数轴上有(500000)个位置,先有两个操作:

    • (1 x y:)表示(a[x])加上(y)
    • (2 x y:)表示对所有满足条件的位置的(a_i)求和,这里的满足条件是(i\% x=y)

    (500000)次询问,对每次(2)操作输出答案。

    思路:

    • 注意到如果(x)比较大,那么我们可以直接暴力的,所以考虑分块。
    • 修改的话直接暴力修改,如果(x>E),我们就直接暴力询问;否则,直接输出预处理的值。
    • 怎么预处理呢?我们首先让(E=sqrt{500000}=750),注意到(E,y)都很小,那么我们就开一个数组(pos[x][y])表示模(x)(y)所有位置数的和。
    • 修改的话同时修改(pos)数组即可。

    详见代码:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define INF 0x3f3f3f3f3f3f3f3f
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 500005, E = 750;
    int q;
    int pos[E][E]; // % x = y
    int a[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> q;
        while(q--) {
            int op, x, y; cin >> op >> x >> y;
            if(op == 1) {
                a[x] += y;
                for(int i = 1; i < E; i++) {
                    pos[i][x % i] += y;
                }
            } else {
                if(y < 0) y += x;
                if(x < E) {
                    cout << pos[x][y] << '
    ';
                } else {
                    int ans = 0;
                    for(int i = y; i < N; i += x) ans += a[i];
                    cout << ans << '
    ';
                }
            }
        }
        return 0;
    }
    

    G.Indie Album

    题意:
    现有两种操作:

    • (1 c:)表示以(c)开头,重新建立一个字符串;
    • (2 j c:)表示在第(j)个版本后面加上一个字符(c),注意每次操作版本都会更新。

    同时有多组询问,每组询问如:("i t")的格式,询问(t)这个字符串在第(i)个版本的字符串中出现了多少次。

    思路:
    类似于阿狸的打字机,考虑离线处理问题。

    • 对于1操作,注意到其实并不用重新建立自动机,我们只用关注每个版本的(end)位置就好,所以直接拿一个数组记录每个版本的(end)位置即可。
    • 同时处理出每个询问串所在AC自动机上面的位置。
    • 之后就类似于阿狸打字机的套路,将(fail)树建出来,跑出(dfs)序,用树状数组维护前缀链即可。
    • 啥,为啥是前缀链?
    • 不就是(fail)树求子子串个数的套路么?若(x)串在(y)串中,那么(y)的前缀链肯定存在一个点其(fail)是指向(x)的,即在(fail)树上点(x)的子树中。那问题不就是子树求和么。

    思路就是这样,但注意一个细节,最后dfs的时候会走错点!!因为我们建fail的时候改变了儿子信息。所以可以事先拿个数组保存一下。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    using namespace std;
    typedef long long ll;
    const int N = 1e6 + 5, MAX = 26;
    queue <int> q;
    int nd[N], in[N], out[N], T;
    int res[N], c[N];
    vector <pair<int, int> > v[N];
    int lowbit(int x){return x & (-x);}
    void upd(int x, int v) {
        for(; x < N; x += lowbit(x)) c[x] += v;
    }
    int query(int x) {
        int ans = 0;
        for(; x; x -= lowbit(x)) ans += c[x];
        return ans;
    }
    int query(int l, int r) {
        return query(r) - query(l - 1);
    }
    struct ACAM{
        int sz;
        int ch[N][MAX], ch2[N][MAX];
        int fail[N];
        vector <int> g[N];
        int newnode() {
            memset(ch[++sz], 0, sizeof(ch[sz]));
            fail[sz] = 0;
            return sz;
        }
        void init() {
            sz = -1;
            newnode();
        }
        int insert(int u, char *s) {
            int len = strlen(s);
            for(int i = 0; i < len; i++) {
                if(!ch[u][s[i] - 'a']) ch[u][s[i] - 'a'] = newnode();
                u = ch[u][s[i] - 'a'];
            }
            return u;
        }
        void build() {
            for(int i = 0; i <= sz; i++) {
                for(int j = 0; j < 26; j++) {
                    ch2[i][j] = ch[i][j];
                }
            }
            for(int i = 0; i < 26; i++) {
                if(ch[0][i]) q.push(ch[0][i]);
            }
            while(!q.empty()) {
                int cur = q.front(); q.pop();
                g[fail[cur]].push_back(cur);
                for(int i = 0; i < 26; i++) {
                    if(ch[cur][i]) {
                        fail[ch[cur][i]] = ch[fail[cur]][i];
                        q.push(ch[cur][i]);
                    } else {
                        ch[cur][i] = ch[fail[cur]][i];
                    }
                }
            }
        }
        void pre(int u) {
            in[u] = ++T;
            for(auto it : g[u]) pre(it);
            out[u] = T;
        }
        void dfs(int u) {
            upd(in[u], 1);
            for(auto it : v[u]) {
                res[it.second] = query(in[it.first], out[it.first]);
            }
            for(int i = 0; i < 26; i++) {
                if(ch2[u][i]) dfs(ch2[u][i]);
            }
            upd(in[u], -1);
        }
    }ac;
    int n;
    char s[2], str[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        ac.init();
        for(int i = 1; i <= n; i++) {
            int op; cin >> op;
            if(op == 1) {
                cin >> s;
                nd[i] = ac.insert(0, s);
            } else {
                int x; cin >> x >> s;
                nd[i] = ac.insert(nd[x], s);
            }
        }
        int q; cin >> q;
        for(int i = 1; i <= q; i++) {
            int x; cin >> x >> str;
            v[nd[x]].push_back(MP(ac.insert(0, str), i));
        }
        ac.build();
        ac.pre(0);
        ac.dfs(0);
        for(int i = 1; i <= q; i++) cout << res[i] << '
    ';
        return 0;
    }
    
  • 相关阅读:
    c c++ 混合编译
    vlc sdl 播放视频可随窗口改变大小
    exec函数族的使用
    gcc编译器命令使用详解
    linux gcc 编译时头文件和库文件搜索路径
    VLC1.2 播放视频迟滞卡
    Ubuntu 中软件的安装、卸载以及查看的方法总结
    SDL2.0 VLC ubuntu安装和黑屏问题
    linux动态库与静态库混合连接
    FFMEPG -- A ffmpeg and SDL Tutorial : tutorial05
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11440797.html
Copyright © 2011-2022 走看看