20240819总结

总分 \(400 pts\),得分为 \(40 pts\),鉴定为史上最菜的 Oier。

card

每次修改相当于添加一个数和删除一个数,考虑添加一个数,如果覆盖的区间没有其他的,则自己不用修改,如果有,就需要修改,如果覆盖区间超过了自己数值,则超出的部分都需要修改。

#include<iostream>

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}

const int N = 2e5 + 10;
int n, m, ans;
int a[N], cnt[N], tot[N];
void add(int x){
    cnt[x]++;
    if (x - cnt[x] + 1 >= 1){
        if (!tot[x - cnt[x] + 1]) ans++;
        tot[x - cnt[x] + 1]++;
    }
}
void del(int x){
    if (x - cnt[x] + 1 >= 1){
        tot[x - cnt[x] + 1]--;
        if (!tot[x - cnt[x] + 1]) ans--;
    }
    cnt[x]--;
}

int main(){
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read(), add(a[i]);
    for (int i = 1; i <= m; i++){
        int x = read(), y = read();
        del(a[x]);
        add(a[x] = y);
        cout << n - ans << '\n';
    }
    return 0;
}

sort

可以发现性质,奇数位上的和模 \(11\),等于偶数位上的和模 \(11\),设 \(dp_{i,j}\) 表示用 \(i\) 个数,凑出余 \(j\) 的方案数个数。

在高位从 \(9\) 枚举到 \(0\),看是否能填入,如果能,就填,如何判断?将 \(dp\) 退掉 \(9\) 之后再看是否能满足上面结论。

#include<iostream>
#include<cstring>

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}

const int N = 1e3 + 10;
char c[N];
int n, cnt, sum;
int f[N][12], tot[12];
void add(int x){
    for (int i = cnt; i >= 0; i--){
        for (int j = 0; j <= 10; j++){
           f[i + 1][(j + x) % 11] += f[i][j]; 
        }
    }
    tot[x]++, cnt++;
}
void del(int x){
    for (int i = 0; i <= cnt; i++){
        for (int j = 0; j <= 10; j++){
            f[i + 1][(j + x) % 11] -= f[i][j];
        }
    }
    tot[x]--, cnt--;
}

int main(){
    cin >> c + 1;
    n = strlen(c + 1);
    f[0][0] = 1;
    for (int i = 1; i <= n; i++) add(c[i] - '0'), sum += c[i] - '0';
    int s = sum * 6 % 11, fir, sec, now1 = s, now2 = s;
    for (int i = 1; i <= n; i++){
        if (i & 1) fir = n / 2 - i / 2, sec = now1;
        else fir = (n + 1) / 2 - (i + 1) / 2, sec = now2;
        int x = 9;
        while (1){
            if (!tot[x]){
                x--;
                continue;
            }
            del(x);
            if (f[fir][sec]) break;
            add(x);
            x--;
        }
        if (i & 1) now2 = (now2 - x + 11) % 11;
        else now1 = (now1 - x + 11) % 11;
        cout << x;
    }
    return 0;
}

offsheet

看到此题,第一眼费用流,但是暴力建边时间复杂度会爆炸,由于要求 \(|x_1-x_2|+|y_1-y_2|\) 的最大值,则用四个点连边,分别代表 \(x_1+x_2\)\(x_1-x_2\)\(-x_1+x_2\)\(-x_1-x_2\),这样就能跑费用流了。

#include<iostream>
#include<queue>
#define int long long
#define INF 1e17

using namespace std;

inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}

const int N = 5e4 + 10, M = 1e5 + 10;
int n, s, t, ans;
struct edge{
    int v, w, c, nxt;
}e[M << 1];
int head[N], cnt = 1;
void add_edge(int u, int v, int w, int c){
    e[++cnt] = (edge){v, w, c, head[u]};
    head[u] = cnt;
}
void add(int u, int v, int w, int c){
    add_edge(u, v, w, c);
    add_edge(v, u, 0, -c);
}
int dis[N], cur[N];
bool vis[N], flag[N];
queue<int> q;
bool spfa(){
    for (int i = s; i <= t; i++) dis[i] = -INF, vis[i] = 0;
    dis[s] = 0, vis[s] = 1;
    q.push(s);
    while (!q.empty()){
        int u = q.front();
        vis[u] = 0;
        q.pop();
        for (int i = head[u]; i; i = e[i].nxt){
            int v = e[i].v;
            if (e[i].w > 0 && dis[v] < dis[u] + e[i].c){
                dis[v] = dis[u] + e[i].c;
                if (!vis[v]) vis[v] = 1, q.push(v);
            }
        }
    }
    return dis[t] != -INF;
}
int dfs(int u, int sum){
    if (u == t) return sum;
    int res = 0;
    flag[u] = 1;
    for (int i = cur[u]; i; i = e[i].nxt){
        cur[u] = i;
        int v = e[i].v;
        if (e[i].w > 0 && dis[v] == dis[u] + e[i].c && !flag[v]){
            int s = dfs(v, min(sum, e[i].w));
            e[i].w -= s, e[i ^ 1].w += s;
            res += s, sum -= s, ans += s * e[i].c;
            if (sum == 0) return res;
        }
    }
    flag[u] = 0;
    return res;
}
void Dinic(){
    while (spfa()){
        for (int i = s; i <= t; i++) cur[i] = head[i], flag[i] = 0;
        dfs(s, INF);
    }
}

signed main(){
    n = read();
    s = 0, t = 2 * n + 5;
    for (int i = 1; i <= n; i++){
        int x = read(), y = read(), c = read();
        add(s, i, c, 0);
        add(i, 2 * n + 1, c, x + y);
        add(i, 2 * n + 2, c, x - y);
        add(i, 2 * n + 3, c, -x + y);
        add(i, 2 * n + 4, c, -x - y);
    }
    for (int i = 1; i <= n; i++){
        int x = read(), y = read(), c = read();
        add(i + n, t, c, 0);
        add(2 * n + 1, i + n, c, -x - y);
        add(2 * n + 2, i + n, c, -x + y);
        add(2 * n + 3, i + n, c, x - y);
        add(2 * n + 4, i + n, c, x + y);
    }
    Dinic();
    cout << ans;
    return 0;
}
posted @ 2024-08-20 17:31  bryce_yyds  阅读(27)  评论(1)    收藏  举报