zoukankan      html  css  js  c++  java
  • 2019 Multi-University Training Contest 6

    2019 Multi-University Training Contest 6

    B.Nonsense Time

    首先有这样一个结论:随机生成序列的期望(LIS)长度为(O(sqrt{n}))
    然后就可以愉快的暴力了。
    考虑逆序时间,即每次删去一个数,并回答询问。
    因为限制(LIS)的长度为(sqrt{n}),那么期望删除(sqrt{n})次才会修改(LIS)长度,这个时候暴力更新(LIS)即可。
    复杂度(O(nlognsqrt{n})),求(LIS)并且得到(LIS)序列可用树状数组来搞,复杂度是(O(nlogn))的。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5e5 + 5;
    int T, n;
    int a[N], b[N], c[N], d[N], nxt[N], pre[N];
    bool used[N];
    int f[N], g[N];
    int lowbit(int x) {
        return x & (-x);
    }
    int query(int x) {
        int ans = 0, p = 0;
        for(; x; x -= lowbit(x)) {
            if(c[x] > ans) {
                ans = c[x];
                p = d[x];
            }
        }
        return p;
    }
    void update(int p, int x, int v) {
        for(; x < N; x += lowbit(x)) {
            if(c[x] < v) {
                c[x] = v; d[x] = p;
            }
        }
    }
    int build() {
        int tot = 0, p = 0;
        for(int i = 1; i <= n; i++) used[i] = 0;
        for(int i = nxt[0]; i <= n; i = nxt[i]) {
            int k = query(a[i] - 1);
            f[i] = f[k] + 1;
            if(f[i] > tot) tot = f[i], p = i;
            update(i, a[i], f[i]);
            g[i] = k;
        }
        used[p] = 1;
        while(g[p]) used[p = g[p]] = 1;
        for(int i = 1; i <= n; i++)
            for(int j = i; j < N; j += lowbit(j)) c[j] = d[j] = 0;
        return tot;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n;
            for(int i = 1; i <= n; i++) cin >> a[i];
            for(int i = 1; i <= n; i++) cin >> b[i];
            for(int i = 0; i <= n; i++) nxt[i] = i + 1;
            for(int i = n + 1; i; i--) pre[i] = i - 1;
            int ans = build();
            vector <int> res;
            for(int i = n; i >= 1; i--) {
                res.push_back(ans);
                pre[nxt[b[i]]] = pre[b[i]];
                nxt[pre[b[i]]] = nxt[b[i]];
                if(used[b[i]]) ans = build();
            }
            reverse(res.begin(), res.end());
            for(int i = 0; i < res.size(); i++) cout << res[i] << " 
    "[i == res.size() - 1];
        }
        return 0;
    }
    

    E.Snowy Smile

    先对横纵坐标离散化,之后(O(n^2))枚举上下边界,下边界扫过去时维护(y)的和,之后解决的就是一个最大连续子段和的问题。
    因为是动态维护,考虑线段树。详见代码:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 2005;
    int T;
    int x[N], y[N], w[N];
    int a[N], b[N];
    struct SEG{
        ll sum[N << 2], maxv[N << 2], lmax[N << 2], rmax[N << 2];
        void push_up(int o) {
            sum[o] = sum[o << 1] + sum[o << 1|1];
            maxv[o] = max(maxv[o << 1], max(maxv[o << 1|1], rmax[o << 1] + lmax[o << 1|1]));
            lmax[o] = max(lmax[o << 1], sum[o << 1] + lmax[o << 1|1]);
            rmax[o] = max(rmax[o << 1|1], sum[o << 1|1] + rmax[o << 1]);
        }
        void build(int o, int l, int r) {
            sum[o] = maxv[o] = lmax[o] = rmax[o] = 0;
            if(l == r) return;
            int mid = (l + r) >> 1;
            build(o << 1, l, mid); build(o << 1|1, mid + 1, r);
        }
        void update(int o, int l, int r, int p, int v) {
            if(l == r) {
                sum[o] += v;
                maxv[o] = lmax[o] = rmax[o] = sum[o];
                return ;
            }
            int mid = (l + r) >> 1;
            if(p <= mid) update(o << 1, l, mid, p, v);
            else update(o << 1|1, mid + 1, r, p, v);
            push_up(o);
        }
    }seg;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            a[0] = b[0] = 0;
            int n; cin >> n;
            for(int i = 1; i <= n; i++) {
                cin >> x[i] >> y[i] >> w[i];
                a[++a[0]] = x[i];
                b[++b[0]] = y[i];
            }
            sort(a + 1, a + a[0] + 1);
            sort(b + 1, b + b[0] + 1);
            a[0] = unique(a + 1, a + a[0] + 1) - a - 1;
            b[0] = unique(b + 1, b + b[0] + 1) - b - 1;
            vector <pii> v[N];
            for(int i = 1; i <= n; i++) {
                x[i] = lower_bound(a + 1, a + a[0] + 1, x[i]) - a;
                y[i] = lower_bound(b + 1, b + b[0] + 1, y[i]) - b;
                v[x[i]].push_back(MP(y[i], w[i]));
            }
            ll ans = 0;
            for(int i = 1; i <= a[0]; i++) {
                seg.build(1, 1, b[0]);
                for(int j = i; j <= a[0]; j++) {
                    for(auto P : v[j]) {
                        seg.update(1, 1, b[0], P.first, P.second);
                    }
                    ans = max(ans, seg.maxv[1]);
                }
            }
            cout << ans << '
    ';
        }
        return 0;
    }
    

    F.Faraway

    每个点会将平面分为四个部分,在每个部分距离的绝对值是可以直接去掉的。
    最终被(n)个点划分的平面有(n^2)个,那么就枚举每一个平面,考虑统计答案。因为(lcm(2,3,4,5)=60),所以我们(60*60)枚举横纵坐标,判合法之后统计答案即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 15;
    int T;
    int n, m;
    int x[N], y[N], k[N], t[N];
    int a[N], b[N];
    int na, nb;
    bool check(int X, int Y) {
        for(int i = 1; i <= n; i++) {
            if((abs(X - x[i]) + abs(Y - y[i])) % k[i] != t[i]) return 0;
        }
        return 1;
    }
    ll calc(int l, int r) {
        int len = r - l - 1;
        if(len < 0) return 0;
        return len / 60 + 1;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n >> m;
            a[na = 1] = b[nb = 1] = m + 1;
            for(int i = 1; i <= n; i++) {
                cin >> x[i] >> y[i] >> k[i] >> t[i];
                a[++na] = x[i]; b[++nb] = y[i];
            }
            sort(a + 1, a + na + 1);
            sort(b + 1, b + nb + 1);
            ll ans = 0;
            for(int i = 0; i < na; i++) if(a[i] < a[i + 1])
                for(int j = 0; j < nb; j++) if(b[j] < b[j + 1])
                    for(int X = 0; X < 60; X++) {
                        for(int Y = 0; Y < 60; Y++) {
                            if(check(a[i] + X, b[j] + Y))
                                ans += calc(a[i] + X, a[i + 1]) * calc(b[j] + Y, b[j + 1]);
                        }
                    }
            cout << ans << '
    ';
        }
        return 0;
    }
    

    K.11 Dimensions

    先求出(dp[i,j]),表示处理了后面(i)位,且模(m)余数为(j)的总方案数。
    因为题目要求字典序第(k)小,所以就考虑逐位确定。注意到有很多个"?"的话,前面很多都是取(0)的,因为每个位置有(10)种选择,(20)个位置就有(10^{20})种选择了,所以逐位确定时只用考虑后面(20)个位置。
    因为(dp)已经求出了方案,后面直接gao就行。
    代码如下:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int N = 50005, MOD = 1e9 + 7;
    const ll inf = 1ll << 61;
    int T;
    int n, m, q;
    ll pw[N], pwm[N];
    ll dp[N][22];
    char s[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        pw[0] = pwm[0] = 1;
        for(int i = 1; i < N; i++) pw[i] = pw[i - 1] * 10 % MOD;
        vector <int> p;
        while(T--) {
            p.clear();
            cin >> n >> m >> q >> s + 1;
            for(int i = 1; i <= n + 1; i++) pwm[i] = pwm[i - 1] * 10 % m;
            for(int i = 0; i <= n; i++) {
                for(int j = 0; j < m; j++) dp[i][j] = 0;
            }
            dp[0][0] = 1;
            ll ans = 0, sum = 0;
            for(int i = 1; i <= n; i++) {
                char ch = s[n - i + 1];
                if(ch == '?') {
                    p.push_back(i - 1);
                    for(int j = 0; j < 10; j++) {
                        for(int k = 0; k < m; k++) {
                            int tmp = (j * pwm[i - 1] % m + k) % m;
                            dp[i][tmp] += dp[i - 1][k];
                            if(dp[i][tmp] > inf) dp[i][tmp] = inf;
                        }
                    }
                } else {
                    for(int k = 0; k < m; k++) {
                        dp[i][k] += dp[i - 1][k];
                        if(dp[i][k] > inf) dp[i][k] = inf;
                    }
                    ans = (ans + (ch - '0') * pw[i - 1]) % MOD;
                    sum = (sum + (ch - '0') * pwm[i - 1]) % m;
                }
            }
            int c = min(30, (int)p.size());
            ll Ans = ans;
            while(q--) {
                ll k; cin >> k;
                ans = Ans;
                int f = (m - sum) % m;
                if(dp[n][f] < k) {
                    cout << -1 << '
    ';
                    continue;
                }
                f = sum;
                for(int i = c - 1; i >= 0; i--) {
                    for(int j = 0; j < 10; j++) {
                        int now = (m - (f + j * pwm[p[i]]) % m) % m;
                        if(dp[p[i]][now] >= k) {
                            f = (f + j * pwm[p[i]]) % m;
                            ans = (ans + 1ll * j * pw[p[i]]) % MOD;
                            break;
                        } else k -= dp[p[i]][now];
                    }
                }
                cout << ans << '
    ';
            }
        }
        return 0;
    }
    

    H.TDL

    ((f(n,m)-n)) ^ (n=k ->f(n,m)=n) ^ (k)
    打表发现(f(n,m))在给定数据范围内好像不超过600,那么暴力枚举(n)(k-600)~(k+600)就行了。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T;
    ll k;
    int m;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> k >> m;
            ll ans = -1;
            int f = 1;
            for(ll i = max(1ll, k - 650); f && i <= k + 650; i++) {
                int cnt = 0;
                for(ll j = i + 1;; j++) {
                    if(__gcd(i, (ll)j) == 1) cnt++;
                    if(cnt == m) {
                        if((i + (i ^ k)) == j) f = 0, ans = i;
                        break;
                    }
                }
            }
            cout << ans << '
    ';
        }
        return 0;
    }
    

    L.Stay Real

    签到题。贪心取即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e5 + 5, INF = 0x3f3f3f3f;
    int t, n, a[MAXN];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> t;
        while (t--) {
            ll ans[2] = { 0 };
            cin >> n;
            for (int i = 1; i <= n; i++) {
                cin >> a[i];
            }
            sort(a + 1, a + 1 + n, greater<int>());
            int now = 0;
            for (int i = 1; i <= n; i++) {
                ans[now] += a[i];
                now ^= 1;
            }
            cout << ans[0] << ' ' << ans[1] << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    下一个ajax异步请求被挂起问题
    借鉴别人的Oracle 11g安装和卸载图文教程
    Html5 实现网页截屏 页面生成图片(图文)
    Oracle修改字段类型方法小技巧
    基于轻量级ORM框架Dapper的扩展说明
    JavaScript+html5 canvas实现本地截图教程
    SkipList跳表基本原理
    Oracle日期查询:季度、月份、星期等时间信息
    设计模式之模板模式
    设计模式之解释器模式
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11332739.html
Copyright © 2011-2022 走看看