• Codeforces Round #620 (Div. 2)


    传送门

    A. Two Rabbits

    签到。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 21:05:55
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int x, y, a, b;
     
    void run(){
        cin >> x >> y >> a >> b;
        if((y - x) % (a + b) == 0) {
            cout << (y - x) / (a + b) << '
    ';    
        } else cout << -1 << '
    ';
    }
     
    int main() {
        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. Longest Palindrome

    (map)乱搞即可。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 21:09:39
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 100 + 5;
     
    string rev(string s) {
        reverse(all(s));   
        return s;
    }
     
    int n, m;
    string s[N];
    map <string, int> mp;
     
    void run(){
        for(int i = 1; i <= n; i++) {
            cin >> s[i];
            mp[s[i]]++;
        }
        string ans = "", res = "";
        for(int i = 1; i <= n; i++) {
            if(mp[s[i]] && mp[rev(s[i])]) {
                string rs = rev(s[i]);
                if(s[i] == rs) {
                    res = s[i];   
                } else {
                    mp[s[i]]--;
                    mp[rs]--;
                    ans += s[i];
                }
            }   
        }
        string ans2 = rev(ans);
        ans += res;
        ans += ans2;
        cout << sz(ans) << '
    ';
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m) run();
        return 0;
    }
    

    C. Air Conditioner

    贪心。
    每次我们找能够走到的一个区间,然后和能使客人满意的区间取交集,若交集不为空,则能够满足当前客人。
    之后类似这样操作就行。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 21:19:20
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 100 + 5;
     
    int n, m;
    ll t[N], l[N], r[N];
     
    void run(){
        cin >> n >> m;
        for(int i = 1; i <= n; i++) {
            cin >> t[i] >> l[i] >> r[i];   
        }
        ll prel = m, prer = m;
        for(int i = 1; i <= n; i++) {
            int d = t[i] - t[i - 1];
            prer = min(r[i], prer + d);
            prel = max(l[i], prel - d);
            if(prel > r[i] || prer < l[i]) {
                cout << "NO" << '
    ';
                return;   
            }
        }
        cout << "YES" << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int q; cin >> q;
        while(q--) run();
        return 0;
    }
    

    D. Shortest and Longest LIS

    题意:
    先有一个长度为(n)的排列,但每个位置的具体数字没有给出,只给出了一个长度为(n-1)且只包含("<,>")两个字符。

    • 若第(i)个位置为(">"),那么(a_i>a_{i+1})
    • 若第(i)个位置为("<"),那么(a_i<a_{i+1})

    现在要构造出两个排列,一个使得(LIS)长度最小,一个使得(LIS)长度最大。

    思路:
    很容易想到(Dilworth)定理:

    • 集合的最小链划分等于其最长反链,集合的最小反链划分等于其最长链。

    这里的链抽象来说,就是给出一个二元关系,链上面的任意两个元素都可比;反链即任意两个元素都不可比。

    (LIS)长度最小举例,也就是说不相交的下降子序列集合个数最少,那么我们贪心考虑,显然越前面越大即可。
    (LIS)长度最大的话,前面越小就行。
    剩下的就是构造。
    (LIS)长度最小举例,就是找到第一个("<")符号,那个位置为目前最小值,然后依次更新前面的(">");之后重复该过程即可。
    最后一个位置要特殊处理。
    还有一种更好写的方法,就是第一个位置设为(INF),后面要减小就减一,增大就加上(INF)。最后离散化一波即可。
    详见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 21:34:37
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int n;
    char s[N];
    int a[N], b[N];
    int big[N], small[N];
    bool chk[N];
     
    void run(){
        cin >> n;
        cin >> (s + 1);
        int t1 = 0, t2 = 0;
        for(int i = 1; i < n; i++) {
            if(s[i] == '>') big[++t1] = i;
            else small[++t2] = i;
        }
        big[++t1] = n;
        small[++t2] = n;
        int Max = n, Min = 1;
        for(int i = 1; i <= n; i++) chk[i] = false;
        for(int i = 1; i <= t1; i++) {
            a[big[i]] = Max--;
            chk[big[i]] = true;
            int p = big[i] - 1;
            while(p > 0 && !chk[p]) {
                chk[p] = true;
                a[p] = Max--;
                --p;   
            }
        }
        for(int i = 1; i <= n; i++) chk[i] = false;
        for(int i = 1; i <= t2; i++) {
            b[small[i]] = Min++;
            chk[small[i]] = true;
            int p = small[i] - 1;
            while(p > 0 && !chk[p]) {
                chk[p] = true;
                b[p] = Min++;
                --p;   
            }
        }   
        for(int i = 1; i <= n; i++) cout << a[i] << " 
    "[i == n];
        for(int i = 1; i <= n; i++) cout << b[i] << " 
    "[i == n];
    }
     
    int main() {
        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. 1-Trees and Queries

    题意:
    给出一颗树,然后给出(q)个询问:(x y a b k),回答现在在树上加一条边((x,y)),然后从(a)走到(b),能否刚好走(k)次。

    思路:
    显然我们只需要求(a ightarrow b)的最短路劲(d),然后看(d)(k)的奇偶性是否相同就行。
    很容易发现((x,y))这条边至多走一次,那么就三种情况都看看就行。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 22:18:17
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int n, q;
     
    int f[N][20], deep[N];
     
    struct Edge {
        int v, next;   
    }e[N << 1];
    int head[N], tot;
    void adde(int u, int v) {
        e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;   
    }
     
    void dfs(int u, int fa) {
        deep[u] = deep[fa] + 1;
        f[u][0] = fa;
        for(int i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if(v != fa) dfs(v, u);
        }
    }
     
    int LCA(int x, int y) {
        if(deep[x] < deep[y]) swap(x, y);
        for(int i = 19; i >= 0; i--) {
            if(deep[f[x][i]] >= deep[y]) x = f[x][i];
        }   
        if(x == y) return x;
        for(int i = 19; i >= 0; i--) {
            if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];   
        }
        return f[x][0];
    }
     
    int dis(int x, int y) {
        int z = LCA(x, y);
        return deep[x] + deep[y] - 2 * deep[z];   
    }
     
    bool solve(int a, int b, int c, int d, int k, int v) {
        int t = dis(a, b) + v + dis(c, d);
        if(t <= k && ((k & 1) == (t & 1))) return true;
        return false;
    }
     
    void run(){
        memset(head, -1, sizeof(head));
        for(int i = 1; i < n; i++) {
            int u, v; cin >> u >> v;
            adde(u, v); adde(v, u);   
        }
        dfs(1, 0);
        for(int i = 1; i < 20; i++) {
            for(int j = 1; j <= n; j++) {
                f[j][i] = f[f[j][i - 1]][i - 1];
            }   
        }
        cin >> q;
        while(q--) {
            int x, y, a, b, k;
            cin >> x >> y >> a >> b >> k;
            if(solve(a, a, a, b, k, 0) || solve(a, x, y, b, k, 1) || solve(a, y, x, b, k, 1)) {
                cout << "YES" << '
    ';
            } else cout << "NO" << '
    ';
        }
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n) run();
        return 0;
    }
    

    F2. Animal Observation (hard version)

    题意:
    给出一个(n*m,nleq 50,mleq 2cdot 10^4)的矩阵,每个格子有一定数量的物品。
    现在对于每一行,可以放置一个(2*k)的矩阵,放上去可以取走矩阵范围内的物品(若在最后一行则放置(1*k))的矩阵。
    放置的矩阵可以重叠,但不能重复取走格子内的物品。
    问最多能够取走多少的物品。

    思路:
    先说一下easy版本:esay版本中(kleq 40),我们很容易想到一个(dp:dp_{i,j}:)(i)行将矩阵放置于第(j)个位置最大能取走的数量,因为(k)很小,我们只需要维护前后缀的最大值并同时枚举(k)进行转移即可。
    写起来也不复杂:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/15 22:47:35
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 50 + 5, M = 2e4 + 5;
    
    int n, m, k;
    int dp[N][M];
    int a[N][M], sum[N][M];
    int pre[M], suf[M], id_p[M], id_s[M];
    
    void run(){
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                cin >> a[i][j];
                sum[i][j] = sum[i][j - 1] + a[i][j];   
            }
        }
        auto calc = [&](int i, int a, int b) {
            return sum[i][b] - sum[i][a - 1] + sum[i + 1][b] - sum[i + 1][a - 1];
        };
        auto init = [&](int r) {
            for(int i = k; i <= m; i++) {
                if(dp[r][i] > pre[i - 1]) {
                    pre[i] = dp[r][i];
                } else {
                    pre[i] = pre[i - 1];
                }
            }   
            for(int i = m; i >= k; i--) {
                if(dp[r][i] > suf[i + 1]) {
                    suf[i] = dp[r][i];
                } else {
                    suf[i] = suf[i + 1];
                }
            }
        };
        for(int i = k; i <= m; i++) {
            dp[1][i] = calc(1, i - k + 1, i);   
        }
        init(1);
        for(int i = 2; i <= n; i++) {
            for(int j = k; j <= m; j++) {
                int t = sum[i + 1][j] - sum[i + 1][j - k];
                dp[i][j] = max(pre[j - k], suf[j + k]) + calc(i, j - k + 1, j) - t;
                for(int s = j - k + 1; s <= min(m, j + k - 1); s++) {
                    if(s <= j) dp[i][j] = max(dp[i][j], dp[i - 1][s] + sum[i][j] - sum[i][s]);
                    else dp[i][j] = max(dp[i][j], dp[i - 1][s] + sum[i][s - k] - sum[i][j - k]);
                }
                dp[i][j] += t;
            }
            init(i);
        }
        int ans = pre[m];
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m >> k) run();
        return 0;
    }
    

    hard版本中(kleq m),很显然直接(dp)复杂度为(O(nm^2)),时间复杂度不能承受。
    我们按照滑动窗口的思想来考虑,若第(i-1)行的(dp)值已处理完毕,现在处理第(i)行。我们枚举(j(1leq jleq m-k+1)),假设对于(j)来说,我们对于(dp[i-1][x])都减去了([x,x+k-1])([j,j+k-1])的相交部分。现在从(j)(j+1),会发现(dp[i-1][j-k+1 o j])此时都会加上(animal[i][j]);而(dp[i-1][j+1 o j+k])会减去(animal[i][j+k])
    那么我们对于每一行,暴力枚举(1 o k)进行处理,后面的就类似于一个滑动窗口,用线段树进行区间加减即可,可以做到(O(nmlogm))的复杂度。

    上面的思想抽象来看,每往右移动一次,前缀部分会减少一个位置,他们都会加上同一个值;而后缀部分会增加一个位置,会都减少同一个值。
    也就是说对于(dp[i][j])较优的决策,对于(dp[i][j+1])也是较优的,因此我们可以考虑用一个单调队列来维护决策位置,最后找到决策位置后(O(1))可以计算相交区间的值从而维护答案。
    实现的话从前缀转移过来时正着扫一遍;从后缀转移过来时倒着扫一遍即可。
    这样时间复杂度为(O(nm))
    细节见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/2/17 10:08:57
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 50 + 5, M = 2e4 + 5;
    
    int n, m, k;
    int a[N][M];
    int lmax[M], rmax[M];
    
    int calc(vector<int>& v, int l, int r) {
        return v[r] - v[l - 1];   
    }
    
    int calc(vector<vector<int>>& v, int i, int l, int r) {
        return calc(v[i], l, r) + calc(v[i + 1], l, r);   
    }
    
    void solve(int i, vector<int> res, vector<int> &arr, vector<int> p, int op) {
        if(op) {
            vector <int> t(m + 3);
            for(int j = 1; j <= m; j++) {
                t[j] = p[m - j + 1];
            }
            p.swap(t);
        }
        deque <pii> q;
        for(int j = 1; j <= m - k + 1; j++) {
            int now = (op ? res[m - j - k + 2] : res[j]) - calc(p, j, j + k - 1);
            if(sz(q) && q.front().se <= j - k) q.pop_front();
            while(sz(q) && q.back().fi + calc(p, q.back().se, j - 1) <= now) q.pop_back();
            q.push_back(MP(now, j));
            arr[j] = q.front().fi + calc(p, q.front().se, j - 1);
        }
    }
    
    void run(){
        vector <vector <int>> pre(n + 2, vector<int>(m + 3, 0)), suf(n + 2, vector<int>(m + 3, 0));
        vector <vector <int>> dp(n + 2, vector<int>(m + 3, 0));
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                cin >> a[i][j];
                pre[i][j] = pre[i][j - 1] + a[i][j];
            }
            for(int j = m; j >= 1; j--) {
                suf[i][j] = suf[i][j + 1] + a[i][j];   
            }
        }
        auto init = [&](int i) {
            for(int j = 1; j <= m; j++) {
                lmax[j] = max(lmax[j - 1], dp[i][j]);
            }   
            for(int j = m; j >= 1; j--) {
                rmax[j] = max(rmax[j + 1], dp[i][j]);   
            }
        };
        for(int i = 1; i <= m - k + 1; i++) {
            dp[1][i] = calc(pre, 1, i, i + k - 1);
        }
        init(1);
        for(int i = 2; i <= n; i++) {
            vector <int> dpl(m + 1), dpr(m + 1);
            solve(i, dp[i - 1], dpl, pre[i], 0);
            solve(i, dp[i - 1], dpr, suf[i], 1);
            for(int j = 1; j <= m - k + 1; j++) {
                dp[i][j] = max(lmax[max(0, j - k)], rmax[j + k]) + calc(pre, i, j, j + k - 1);
            }
            for(int j = 1; j <= m - k + 1; j++) {
                dp[i][j] = max(dp[i][j], max(dpl[j], dpr[m - j - k + 2]) + calc(pre, i, j, j + k - 1));
            }
            init(i);
        }
        int ans = lmax[m];
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m >> k) run();
        return 0;
    }
    
  • 相关阅读:
    unity3d 随机生成地形之随机山脉
    unity3d ppsspp模拟器中的post processing shader在unity中使用
    unity3d shader之实时室外光线散射(大气散射)渲染
    Unity3d 游戏中的实时降噪-对Square Enix文档的研究与实现
    Unity3d 获取屏幕depth与normal
    unity3d Hair real time rendering 真实头发实时渲染
    java.net.URL类
    Springboot定时任务
    Base64编码
    ShiroUtil 对密码进行加密
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12322058.html
Copyright © 2020-2023  润新知