zoukankan      html  css  js  c++  java
  • 2018 Multi-University Training Contest 5

    传送门

    B - Beautiful Now

    题意:
    给定(n,kleq 10^9),现在可以执行至多(k)次操作,每次操作交换两个位置上面的数。
    输出最后最小的数和最大的数,不能有前导零。

    思路:
    (n)最多为10位数,显然如果(kgeq 10),我们直接贪心进行排序然后输出即可(注意前导零)。
    下面就考虑(k<10)的情况。
    我们考虑枚举所有的全排列,对于一个(1)~(n)的排列,我们将其变为(1,2,cdots,n),最小的交换次数显然是沿着置换走,那么就沿着置换进行交换就行,这一步复杂度为(O(位数))
    队友想了个贪心的解法,假设我们当前要得到字典序最小,我们就枚举后面所有当前最小的并进行交换,然后依次进行下去,这一步复杂度为(O(9!))。然后有一个优化:如果当前位数就为最小的那个数,就直接进入下一位。这样可能就会比较快了。
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/5/7 14:02:54
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.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
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    
    int a[10], b[10], pos[10], vis[10];
    
    void run() {
        int n, k;
        cin >> n >> k;
        int tot = 0;
        while (n) {
            a[tot++] = n % 10;
            n /= 10;
        }
        reverse(a, a + tot);
        if (k >= tot) {
            sort(a, a + tot);
            for (int i = 0; i < tot; i++) {
                if (a[i] != 0) {
                    cout << a[i];
                    break;
                }
            }
            for (int i = 0; i < tot; i++) {
                if (a[i] == 0) {
                    cout << 0;
                }
            }
            int cnt = 0;
            for (int i = 0; i < tot; i++) {
                if (a[i] != 0 && cnt) cout << a[i];
                if (a[i] != 0) ++cnt;
            }
            cout << ' ';
            reverse(a, a + tot);
            for (int i = 0; i < tot; i++) cout << a[i];
            cout << '
    ';
            return;
        }
        for (int i = 0; i < tot; i++) b[i] = i;
        int ans1 = 2e9, ans2 = -1;
        do {
            if (a[b[0]] == 0) continue;
            for (int i = 0; i < tot; i++) {
                pos[b[i]] = i;
                vis[i] = 0;
            }
            int t = 0;
            for (int i = 0; i < tot; i++) if (!vis[i]) {
                int x = i, len = 0;
                while (!vis[x]) {
                    vis[x] = 1;
                    x = pos[x];
                    ++len;
                }
                t += len - 1;
                if (t > k) break;
            }
            if (t > k) continue;
            int res = 0;
            for (int i = 0; i < tot; i++) {
                res = res * 10 + a[b[i]];
            }
            ans1 = min(ans1, res);
            ans2 = max(ans2, res);
        } while(next_permutation(b, b + tot));
        cout << ans1 << ' ' << ans2 << '
    ';
    }
    
    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;
    }
    

    G - Glad You Came

    题意:
    随机生成(m)组询问((l_i,r_i,v_i)),然后对序列([l_i,r_i])区间上的数取max。(mleq 10^6,nleq 10^5)
    最后输出(displaystyleoplus_{i=1}^nicdot a_i),其中(oplus)为异或。

    思路:
    因为数据是随机生成,所以可以直接通过线段树+减枝解决。
    当然这个题有一个更巧妙的做法,注意到如果两个询问区间相同,我们可以直接取值最大的那个区间。
    那么我们将一组询问的区间([l_i,r_i])拆分为两个长度为(2)的次幂的区间,因为总共有(n)个数,所以一共有(O(nlogn))个区间。之后我们将所有这样的区间下放,每次长度不断减小一半并合并相同区间,复杂度为(O(nlogn))
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/5/8 11:15:33
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.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
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, M = 5e6 + 5;
    
    unsigned int X, Y, Z;
    unsigned int rng61() {
    	X ^= X << 11;
    	X ^= X >> 4;
    	X ^= X << 5;
    	X ^= X >> 14;
    	unsigned int tmp = X ^ Y ^ Z;
    	X = Y;
    	Y = Z;
    	Z = tmp;
    	return Z;
    }
    
    int lg[N];
    void init() {
        lg[2] = 1;
        for (int i = 3; i < N; i++) lg[i] = lg[i >> 1] + 1;
    }
    
    int n, m;
    int f[N][20];
    
    void upd(int &x, int y) {
        if (x < y) x = y;
    }
    
    void run() {
        cin >> n >> m >> X >> Y >> Z;
        for (int i = 1; i <= n; i++) 
            for (int j = 0; j < 20; j++) 
                f[i][j] = 0;
        while (m--) {
    		int L = rng61() % n + 1, R = rng61() % n + 1, v = rng61() & ((1 << 30) - 1);
            if (L > R) swap(L, R);
            int d = lg[R - L + 1];
            upd(f[L][d], v), upd(f[R - (1 << d) + 1][d], v);
        }
        for (int j = 19; j >= 1; j--) {
            for (int i = 1; i + (1 << (j - 1)) <= n; i++) {
                upd(f[i][j - 1], f[i][j]);
                upd(f[i + (1 << (j - 1))][j - 1], f[i][j]);
            }
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            ans ^= 1ll * i * f[i][0];
        }
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    H - Hills And Valleys

    题意:
    给出一个长度为(n,nleq 10^5)的字符串,每个位置为(0)~(9)中的一个数。
    现在可以翻转一段区间,问翻转哪一段区间,可以使得该字符串的最长不下降子序列最长。

    思路:

    • 考虑如果不存在翻转操作,其实就是一个比较简单的(dp)(dp_{i,j})表示匹配了前(i)个字符,最后一个为(j)的方案数。但这个(dp)在有翻转操作存在时就不好处理,因为(dp)的第二维我们不好去转移。
    • 我们可以将这个问题转化一下,就题目给定一个匹配串,然后会有一个模式串(012...9),现在两个串进行匹配,注意模式串中一个字符可以匹配多次,问最长公共上升子序列。
    • 转移的话(dp_{i,j}=max{dp_{i-1,j}+same(i,j),dp_{i,j-1}})
    • 那怎么处理翻转操作呢?这个时候其实就很好处理了,我们只需要翻转模式串即可,最后就形如(012...xy(y-1)...x(y+1)(y+2)...9)这个样子,然后类似求最长公共子序列即可。
    • 因为我们还需要求翻转区间,所以我们还要记录一下状态中第一个(y)出现的位置,最后一个(x)出现的位置即可。

    说点题外话:感觉这里就有点类似(B)题枚举排列时,我们用一个(c)数组来表示排列的下标,我们并不直接枚举原串的全排列,只需要枚举(c)就行。这里也相当于用一个数组来表示第二维(j)的一个顺序。
    细节见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/5/8 11:54:49
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.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
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, M = 13;
    
    int n;
    int f[N][M], fl[N][M], fr[N][M];
    int a[N], b[M], m;
    char s[N];
    int ans, l, r;
    
    void dp(int L, int R) {
        for (int i = 0; i <= m; i++) {
            f[0][i] = 0;
            fl[0][i] = fr[0][i] = -1;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                f[i][j] = f[i - 1][j];
                fl[i][j] = fl[i - 1][j];
                fr[i][j] = fr[i - 1][j];
                if (a[i] == b[j]) {
                    ++f[i][j];
                    if (a[i] == R && fl[i][j] == -1) fl[i][j] = i;
                    if (a[i] == L) fr[i][j] = i;
                }
                if (f[i][j - 1] > f[i][j]) {
                    f[i][j] = f[i][j - 1];
                    fl[i][j] = fl[i][j - 1];
                    fr[i][j] = fr[i][j - 1];
                }
            }
        }
        if (L == 1 && R == 1) {
            l = r = 1;
            ans = f[n][m];
        } else {
            if (f[n][m] > ans && fl[n][m] != -1 && fr[n][m] != -1 && fl[n][m] < fr[n][m]) {
                ans = f[n][m];
                l = fl[n][m], r = fr[n][m];   
            }
        }
    }
    
    void run() {
        cin >> n >> (s + 1);
        for (int i = 1; i <= n; i++) {
            a[i] = s[i] - '0';
        }
        m = 0;
        for (int i = 0; i < 10; i++) {
            b[++m] = i;
        }
        dp(1, 1);
        for (int i = 0; i < 10; i++) {
            for (int j = i + 1; j < 10; j++) {
                m = 0;
                for (int k = 0; k <= i; k++) b[++m] = k;
                for (int k = j; k >= i; k--) b[++m] = k;
                for (int k = j; k < 10; k++) b[++m] = k;
                dp(i, j);
            }
        }
        cout << ans << ' ' << l << ' ' << r << '
    ';
    }
    
    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;
    }
    
  • 相关阅读:
    hive查询结果输出到hdfs上
    重启mysql主从同步mongodb(tungstenreplicator)
    第二个MapReduce
    tungstenreplicator安装
    mysql
    整理requests和正则表达式爬取猫眼Top100中遇到的问题及解决方案
    requests和正则表达式爬取猫眼电影Top100练习
    selenium学习之查找元素(二)
    selenium学习之基本操作(一)
    像素坐标与逻辑坐标的转换
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12856698.html
Copyright © 2011-2022 走看看