省选测试12

T1看错题,暴力没写对,爆0了,QWQ

A 灯

题目大意 : 有m种颜色的灯共n个,每次开启或关上一种颜色的所有,问有几个极长的连续段(注意极长,而不是最长)

  • 对于灯数小于根号的颜色就暴力枚举每个点,对于灯数大于根号的颜色就记录下来,并预处理出这些颜色相互间的影响,而这些颜色种类是不超过根号的,复杂度 \(O(n\sqrt n)\)

Code

Show Code
#include <cmath>
#include <cstdio>
#include <vector>

using namespace std;
const int N = 1e5 + 5, M = 330;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

bool l[N];
vector<int> v[N];
int n, m, q, sq, a[N], cnt[N], tot, id[N], f[M][M], ans, s[N], c[N];

int Cal(int x, int op) {
    ans += cnt[x] * op;
    if (id[x]) {
        ans -= s[x] * op;
        for (int i = 1; i <= tot; ++i)
            if (l[c[i]]) ans -= f[id[x]][i] * op;
    }
    else {
        for (int i = 0; i < v[x].size(); ++i) {
            int y = v[x][i];
            ans -= l[a[y-1]] * op; s[a[y-1]] += op;
            ans -= l[a[y+1]] * op; s[a[y+1]] += op;
        }
    }
    return ans;
}

int main() {
    n = read(); m = read(); q = read();
    for (int i = 1; i <= n; ++i)
        if ((a[i] = read()) == a[i-1]) i--, n--;
    a[n+1] = 0; sq = sqrt(n);
    for (int i = 1; i <= n; ++i) cnt[a[i]]++;
    for (int i = 1; i <= m; ++i)
        if (cnt[i] > sq) c[++tot] = i, id[i] = tot;
    for (int i = 1; i <= n; ++i) {
        if (!id[a[i]]) v[a[i]].push_back(i);
        f[id[a[i-1]]][id[a[i]]]++;
        f[id[a[i]]][id[a[i-1]]]++;
    }
    while (q--) {
        int x = read(); l[x] ^= 1;
        printf("%d\n", Cal(x, l[x] ? 1 : -1));
    }
    return 0;
}

B 十字路口

题目大意 : 给出一个红绿灯系统n个灯在m个时刻的状态,问红绿灯的周期

  • 发现其实就是建图找环

Code

Show Code
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>

using namespace std;
const int N = 1e5 + 5;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

struct Edge {
    int n, t, d;
}e[N];
int h[N], edc;

void Add(int x, int y, int z) {
    e[++edc] = (Edge) {h[x], y, z}; h[x] = edc;
}

bool v[N], g[N];
vector<int> f[N];
int n, m, a[N], i, j, d[N]; 

bool Cmp(int x, int y) {
    return f[i][x] < f[i][y];
}

void Dfs(int x, int dis) {
    d[x] = dis; v[x] = g[x] = 1;
    for (int i = h[x], y; i; i = e[i].n) {
        if (!v[y=e[i].t]) Dfs(y, dis + e[i].d);
        else if (g[y]) {
            printf("%d\n", dis + e[i].d - d[y]);
            exit(0);
        }
    }
    g[x] = 0;
}

int main() {
    m = read(); n = read();
    for (i = 1; i <= n; ++i) {
        f[i].resize(m + 1);
        for (j = 1; j <= m; ++j)
            f[i][j] = read();
    }
    for (i = 1; i <= m; ++i) a[i] = i;
    for (i = 1; i <= n; ++i) {
        sort(a + 1, a + m + 1, Cmp);
        for (j = 2; j <= m; ++j) {
            if (f[i][a[j]] == f[i][a[j-1]]) swap(a[j], a[j-1]);
            else if (f[i][a[j-1]]) Add(a[j-1], a[j], f[i][a[j]] - f[i][a[j-1]]);
        }
    }
    for (i = 1; i <= m; ++i) if (!v[i]) Dfs(i, 0);
    puts("-1");
    return 0;
}

C 密室逃脱

题目大意 : 一条通道里,想要通过需要有一定人数的人一直按着按钮,问保证1号点左面通道的门不会打开,通道里最多可以放多少个人

  • 神仙Dp

Code

Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 1005;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

int n, m, a[N], b[N], f[N][N*20], ans;
//设 f[i][j]表示能到达第 i 个房间的人数恰好为 j 时, 前 i 个房间最多有多少人

int main() {
    n = read(), m = read();
    for (int i = 1; i < n; ++i)
        a[i] = read(), b[i] = read();
    memset(f, 0x8f, sizeof(f));
    for (int i = 0; i < m; ++i) f[1][i] = i;
    for (int i = 1; i < n; ++i) {
        int mx = -2e9;
        for (int j = 0; j < a[i]; ++j) {
            mx = max(mx, f[i][j]);
            f[i+1][j+b[i]] = max(f[i+1][j+b[i]], f[i][j] + b[i]);
        }
        for (int j = 0; j < b[i]; ++j) 
            f[i+1][j] = max(f[i+1][j], mx + j);
        mx = a[i] + b[i];
        for (int j = a[i]; j < mx; ++j)
            f[i+1][j-a[i]] = max(f[i+1][j-a[i]], f[i][j]);
        for (int j = mx; j <= 2e4; ++j)
            f[i+1][j] = max(f[i+1][j], f[i][j]);
    }
    for (int i = 0; i <= 2e4; ++i)
        ans = max(ans, f[n][i]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2021-02-10 13:02  Shawk  阅读(35)  评论(0编辑  收藏  举报