2019牛客多校第八场

大憨熊 提交于 2019-11-27 05:01:40

2019牛客多校第八场

A. All-one Matices

solved at 01:58(+2)

求一个\(n*m\)\(01\)矩阵的极大全\(1\)子矩阵数目

悬线法处理出\(d\)数组(从这个位置最多向上延伸多少个\(1\)),然后单调栈处理出每个位置的\(d\)能延伸的左右最远位置,\(vis\)打标记的时候如果发现标记不是\(i-1\)也不是\(0\)说明这里之前有一个极大矩阵

#include <bits/stdc++.h>
using namespace std;

const int N = 3010;

char a[N][N];
int d[N][N], s[N][N], s2[N][N], n, m, vis[N][N], ans;
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%s", a[i] + 1);
    }
    for(int j = 1; j <= m; ++j) {
        for(int i = 1; i <= n; ++i) {
            if(a[i][j] == '0')
                d[i][j] = 0;
            else
                d[i][j] = d[i - 1][j] + 1;
        }
    }
    for(int i = 1; i <= n; ++i) {
        stack<int> st;
        while(!st.empty()) st.pop();
        d[i][m + 1] = -1;
        st.push(m + 1);
        for(int j = m; j; --j) {
            while(d[i][st.top()] >= d[i][j]) st.pop();
            s[i][j] = st.top() - 1;
            st.push(j);
        }
    }
    for(int i = 1; i <= n; ++i) {
        stack<int> st;
        while(!st.empty()) st.pop();
        d[i][0] = -1;
        st.push(0);
        for(int j = 1; j <= m; ++j) {
            while(d[i][st.top()] >= d[i][j]) st.pop();
            s2[i][j] = st.top() + 1;
            st.push(j);
        }
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            if(a[i][j] == '0') continue;
            int r = s[i][j], l = s2[i][j];
            if(vis[l][r] == i) continue;
            if(vis[l][r] != i - 1 && vis[l][r]) ans++;
            vis[l][r] = i;
        }
    }
    for(int i = 1; i <= m; ++i) 
        for(int j = i; j <= m; ++j) 
            ans += vis[i][j] != 0;
    printf("%d\n", ans);
    return 0;
}

B. Beauty Values

solved at 00:13

定义beauty values为数组中不同的数的数量,求所有区间的beauty values 之和

期望的线性性

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int n, a[N];
long long ans;
vector<int> pos[N];

int main() {
    scanf("%d", &n);
    for(int i = 1; i < N; ++i) pos[i].push_back(0);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        pos[a[i]].push_back(i);
    }
    for(int i = 1; i < N; ++i) {
        for(int j = 1; j < pos[i].size(); ++j) {
            ans += 1LL * (pos[i][j] - pos[i][j - 1]) * (n - pos[i][j] + 1);
        }
    }
    printf("%lld\n", ans);
    return 0;
}

C. CDMA

solved at 01:30

构造一个\(m*m\)的矩阵,元素均为正负一,要求满足任意两行的相应位置乘积之和为\(0\)\(m\)为2的幂次

首先手推出\(m=2\)的解(其实样例已经给了),然后把它复制三边得到一个\(4*4\)的矩阵,把右下角的\(2*2\)个元素取反,就得到了\(m=4\)的解,以此类推即可(我是用的\(m=4\)作为初始矩阵往下推得)

#include <bits/stdc++.h>
using namespace std;

int d[4][4] = {
    {1, 1, 1, 1},
    {1, 1, -1, -1},
    {1, -1, 1, -1},
    {1, -1, -1, 1}
};

int m;
int f(int i, int j, int mod) {
    if(mod == 4) return 1;
    mod /= 2;
    return (i >= mod && j >= mod ? -1 : 1) * f(i % mod, j % mod, mod);
}

int main() {
    scanf("%d", &m);
    if(m == 2) {
        puts("1 1\n1 -1");
        return 0;
    }
    for(int i = 0; i < m; ++i) {
        for(int j = 0; j < m; ++j) {
            printf("%d\t", f(i, j, m) * d[i % 4][j % 4]);
        }
        puts("");
    }
    return 0;
}

D. Distance

upsolved

有一个三维空间,有两种操作,给一个点打上标记,或者查询给定点到所有已标记点中的最小曼哈顿距离,保证三维空间长宽高乘积不超过\(1e5\)

可以定期重构\(bfs\),但是显然三维树状数组更短

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int n, m, h, q, op, x, y, z;

struct BIT {
    static int lowbit(int x) {return x & -x;}
    static void mmax(int &x, int y) {x = (x > y ? x : y);}
    static int index(int i, int j, int k) {return (i - 1) * m * h + (j - 1) * h + k;}
    int c[N];
    void init() {memset(c, 0xc0, sizeof(c));}
    void update(int x, int y, int z, int val) {
        for(int i = x; i <= n; i += lowbit(i)) 
            for(int j = y; j <= m; j += lowbit(j))
                for(int k = z; k <= h; k += lowbit(k))
                    mmax(c[index(i, j, k)], val);
    } 
    int query(int x, int y, int z) {
        int res = -1e9;
        for(int i = x; i; i -= lowbit(i))
            for(int j = y; j; j -= lowbit(j))
                for(int k = z; k; k -= lowbit(k))
                    res = max(res, c[index(i, j, k)]);
        return res;
    }
}T[8];


int main() {
    scanf("%d%d%d%d", &n, &m, &h, &q);
    for(int i = 0; i < 8; ++i) T[i].init();
    while(q--) {
        scanf("%d%d%d%d", &op, &x, &y, &z);
        if(op == 1) {
            for(int mask = 0; mask < 8; ++mask) {
                int tx = x, ty = y, tz = z, vx = x, vy = y, vz = z;
                if(mask & 1) tx = n - tx + 1, vx = -vx;
                if(mask & 2) ty = m - ty + 1, vy = -vy;
                if(mask & 4) tz = h - tz + 1, vz = -vz;
                T[mask].update(tx, ty, tz, vx + vy + vz);
            }
        }
        else {
            int res = 1e9;
            for(int mask = 0; mask < 8; ++mask) {
                int tx = x, ty = y, tz = z, vx = x, vy = y, vz = z;
                if(mask & 1) tx = n - tx + 1, vx = -vx;
                if(mask & 2) ty = m - ty + 1, vy = -vy;
                if(mask & 4) tz = h - tz + 1, vz = -vz;
                res = min(res, vx + vy + vz - T[mask].query(tx, ty, tz));
            }
            printf("%d\n", res);
        }
    }
    return 0;
}

E. Explorer

upsolved

无向图,每条边有上下界限制,只有在上下界之中的数字可以通过这条边,询问有多少种数字可以从\(1\)走到\(n\)

时间分治线段树+可撤销并查集

把size限制看成时间限制就好了

#include <bits/stdc++.h>
using namespace std;
 
const int N = 1e5 + 10;
 
int u[N], v[N], l[N], r[N], b[N << 1], n, m, tot, fa[N], sz[N];
vector<int> g[N << 3];
stack<pair<int*, int>> stk[22];
long long ans;
 
int find(int x) {
    return x== fa[x] ? x : find(fa[x]);
}
 
void update(int rt, int l, int r, int L, int R, int id) {
    if(L <= l && r <= R) {g[rt].push_back(id); return;}
    int mid = l + r >> 1;
    if(L <= mid) update(rt << 1, l, mid, L, R, id);
    if(R > mid) update(rt << 1 | 1, mid + 1, r, L, R, id);
}
 
void dfs(int rt, int l, int r, int dep) {
    while(!stk[dep].empty()) stk[dep].pop();
    for(auto i: g[rt]) {
        int x = find(u[i]), y = find(v[i]);
        if(x == y) continue;
        if(sz[x] < sz[y]) swap(x, y);
        stk[dep].push(make_pair(&sz[x], sz[x]));
        stk[dep].push(make_pair(&fa[y], fa[y]));
        sz[x] += sz[y];
        fa[y] = x;
    }
    if(l == r) {
        if(find(1) == find(n))
            ans += b[r + 1] - b[l];
    }
    else {
        int mid = l + r >> 1;
        dfs(rt << 1, l, mid, dep + 1);
        dfs(rt << 1 | 1, mid + 1, r, dep + 1);
    }
    while(!stk[dep].empty()) {
        *(stk[dep].top().first) = stk[dep].top().second;
        stk[dep].pop();
    }
}
 
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++i) {
        scanf("%d%d%d%d", &u[i], &v[i], &l[i], &r[i]);
        b[2 * i - 1] = l[i];
        b[2 * i] = ++r[i];
    }
    sort(b + 1, b + 2 * m + 1);
    tot = unique(b + 1, b + 2 * m + 1) - b - 1;
    for(int i = 1; i <= m; ++i) {
        l[i] = lower_bound(b + 1, b + tot + 1, l[i]) - b;
        r[i] = lower_bound(b + 1, b + tot + 1, r[i]) - b - 1;
        update(1, 1, tot, l[i], r[i], i);
    }
    for(int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
    dfs(1, 1, tot, 0);
    printf("%lld\n", ans);
    return 0;
}

G. Gemstones

solved at 00:17

签到题,用栈贪心即可

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!