zoukankan      html  css  js  c++  java
  • 【题录】Atcoder ACL#1

    C.Moving Pieces

    走的步数与路径无关,只与棋子的初末位置有关。并且棋子的路径不会碰撞-如果碰撞,可以理解为移动了另外的一颗棋子。因此使用费用流跑一下求出最大收益。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 3000000
    #define INF 99999999
    #define N 505
    int n, m, num, Si, Sj, S, T, dis[maxn], fl[maxn];
    int a[N][N], tag[maxn], mark[N][N], pre[maxn];
    char s[N];
    deque <int> q;
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct edge {
        int cnp = 2, to[maxn], last[maxn], head[maxn], f[maxn], w[maxn];
        void add(int u, int v, int fl, int co) {
            last[cnp] = head[u], to[cnp] = v, f[cnp] = fl, w[cnp] = co, head[u] = cnp ++;
            last[cnp] = head[v], to[cnp] = u, f[cnp] = 0, w[cnp] = -co, head[v] = cnp ++;
        }
    }E;
    
    int id(int x, int y) {
        return (x - 1) * m + y;
    }
    
    void dfs(int x, int y) {
        if(x > n || y > m) return;
        if(a[x][y] == 1) return;
        if(mark[x][y] == num) return;
        mark[x][y] = num;
        E.add(num, id(x, y) + n * m, 1, x + y - Si - Sj);
        dfs(x + 1, y); dfs(x, y + 1);
    }
    
    bool SPFA() {
        for(int i = 1; i <= n * m * 2 + 2; i ++) dis[i] = -INF, fl[i] = 0;
        dis[S] = 0, fl[S] = INF; tag[S] = 1;
        q.push_back(S);
        while(!q.empty()) {
            int u = q.front(); q.pop_front(); tag[u] = 0;
            for(int i = E.head[u]; i; i = E.last[i]) {
                int v = E.to[i];
                if(dis[v] < dis[u] + E.w[i] && E.f[i]) {
                    dis[v] = dis[u] + E.w[i]; pre[v] = i;
                    fl[v] = min(fl[u], E.f[i]);
                    if(!tag[v]) {
                        if((!q.empty()) && (dis[v] > dis[q.front()])) q.push_front(v);
                        else q.push_back(v);
                        tag[v] = 1;
                    }
                }
            }
        }
        return fl[T];
    }
    
    int Solve() {
        int ans = 0;
        while(SPFA()) {
            int now = T; ans += fl[T] * dis[T];
            do {
                int t = pre[now];
                E.f[t] -= fl[T], E.f[t ^ 1] += fl[T];
                now = E.to[t ^ 1];
            }while(now != S);
        }
        return ans;
    }
    
    int main() {
        n = read(), m = read();
        for(int i = 1; i <= n; i ++) {
            scanf("%s", s + 1);
            for(int j = 1; j <= m; j ++)
                if(s[j] == '#') a[i][j] = 1;
                else if(s[j] == 'o') a[i][j] = 2;
        }
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++) {
                if(a[i][j] != 2) continue;
                num = (i - 1) * m + j;
                Si = i, Sj = j;
                dfs(i, j); 
            }
        S = n * m * 2 + 1, T = n * m * 2 + 2;
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
                if(a[i][j] == 2) E.add(S, id(i, j), 1, 0);
        for(int i = 1; i <= n * m; i ++) E.add(i + n * m, T, 1, 0);
        printf("%d
    ", Solve());
        return 0;
    }

    D.Keep Distances

    按照贪心的策略可以从第一个开始,能够跳跃一步就跳跃一步直到跳出去为止。这样可以求出最大集合的大小。考虑把这些跳跃到的点标记为 (a_{1}, a_{2}, ..., a_{k})。再反向贪心一次,同样把跳跃到的点从小到大标记为 (b_{1}, b_{2}, ..., b_{k})。则 ([a_{i}, b_{i}]) 之间的点均出现在最大集合中,而((b_{i}, a_{i + 1})) 这样其余部分的点均不会出现在最大集合中。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 300000
    #define MXB 19
    int n, K, X[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct edge {
        int cnp = 1, opt, last[maxn], head[maxn], to[maxn], deg[maxn], gra[maxn][MXB], sum[maxn][MXB];
        void add(int u, int v) {
            to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
            deg[v] ++;
        }
        void dfs(int u, int fa) {
            gra[u][0] = fa; 
            for(int i = 1; i < MXB; i ++) 
                gra[u][i] = gra[gra[u][i - 1]][i - 1];
            sum[u][0] = u + opt;
            for(int i = 1; i < MXB; i ++) 
                sum[u][i] = sum[u][i - 1] + sum[gra[u][i - 1]][i - 1];
            for(int i = head[u]; i; i = last[i]) {
                int v = to[i];
                dfs(v, u);
            }
        }
        bool cmp(int a, int b) {
            if(!opt) return a <= b;
            else return a >= b;
        }
        int Jump(int a, int b) {
            for(int i = MXB - 1; i >= 0; i --) { 
                if(gra[a][i] && cmp(gra[a][i], b)) a = gra[a][i];
            }
            return a;
        }
    
        int Cal(int a, int b) {
            if(opt && a < b) return 0;
            if(!opt && a > b) return 0; 
            int ans = 0;
            for(int i = MXB - 1; i >= 0; i --) 
                if(gra[a][i] && cmp(gra[a][i], b)) ans += sum[a][i], a = gra[a][i];
            ans += sum[a][0];    
            return ans;
        }    
    }E, E2;
    
    int main() {
        n = read(), K = read(); E.opt = 0, E2.opt = 1;
        E.opt = 0, E2.opt = 1;
        for(int i = 1; i <= n; i ++) X[i] = read();
        for(int i = 1; i <= n; i ++) {
            int l = 1, r = i; 
            while(l < r) {
                int mid = (l + r) >> 1;
                if(mid + 1 <= r) mid += 1;
                if(X[i] - X[mid] >= K) l = mid;
                else r = mid - 1;
            }
            if(X[i] - X[l] >= K) E2.add(l, i);
        }
    //    return 0;
        for(int i = 1; i <= n; i ++) {
            int l = i + 1, r = n;
            while(l < r) {
                int mid = (l + r) >> 1;
                if(X[mid] - X[i] >= K) r = mid;
                else l = mid + 1;
            }
            if(X[l] - X[i] >= K) E.add(l, i);
        }
        for(int i = 1; i <= n; i ++) if(!E.deg[i]) E.dfs(i, 0);
        for(int i = 1; i <= n; i ++) if(!E2.deg[i]) E2.dfs(i, 0);
        int Q = read();
        for(int i = 1; i <= Q; i ++) {
            int l = read(), r = read();
            int t = E.Jump(l, r);
            int t2 = E2.Jump(r, l);
            printf("%d
    ", E2.Cal(r, t2) - E.Cal(l, t));
        }
        return 0;
    }

    E.Shuffle Window

    可以把操作理解为手上时刻有K张牌,每次随机打出一张后可以从牌堆中再摸一张(按顺序)。这样的话考虑独立的两张牌,有两种情况:第一张牌打出去的时候第二张牌还没有拿到手上;第一张牌还未打出时已经摸到了第二张牌。第一种情况下逆序对的个数不会改变,而第二种情况下则有二分之一的可能性可以改变原有的逆序对/创造一个新的逆序对。

    #include <bits/stdc++.h>
    using namespace std;
    #define mod 998244353
    #define maxn 2000000 
    #define lowbit(i) (i & (-i)) 
    int n, K, ans, a[maxn], f[maxn], inv2, sum, fac[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k; 
    }
    
    int mul(int a, int b) {
        return 1ll * a * b % mod;
    }
    
    int add(int a, int b) {
        a += b; if(a >= mod) a -= mod;
        return a;
    }
    
    int sub(int a, int b) {
        a -= b; if(a < 0) a += mod;
        return a;
    }
    
    void Up(int &a, int b) {
        a += b; if(a >= mod) a -= mod;
    }
    
    int Qpow(int x, int t) {
        int base = 1;
        for(; t; t >>= 1, x = mul(x, x))
            if(t & 1) base = mul(base, x);
        return base;
    }
    
    struct FW {
        int C[maxn];
        void Mod(int x, int y) {
            for(int i = x; i <= n; i += lowbit(i)) Up(C[i], y); 
        }
        int Cal(int x) {
            int ans = 0;
            for(int i = x; i; i -= lowbit(i)) Up(ans, C[i]);
            return ans;
        }
    }C1; 
    
    signed main() {
        n = read(), K = read(); inv2 = Qpow(2, mod - 2);
        int invK = Qpow(K, mod - 2), P = mul(K - 1, invK);
        for(int i = 1; i <= n; i ++) a[i] = read(); 
        for(int i = K + 1; i <= n; i ++) f[i] = f[i - 1] + 1;
        for(int i = 1; i <= n; i ++) {
            int num = C1.Cal(a[i] - 1);
            Up(ans, mul(inv2, mul(Qpow(P, f[i]), num)));
            num = sub(sum, num);
            ans = sub(ans, mul(inv2, mul(Qpow(P, f[i]), num)));
            Up(sum, Qpow(Qpow(P, f[i]), mod - 2));
            C1.Mod(a[i], Qpow(Qpow(P, f[i]), mod - 2));
        }
        for(int i = 1; i <= n; i ++) C1.C[i] = 0;
        for(int i = 1; i <= n; i ++) {
            int t = C1.Cal(a[i] - 1);
            Up(ans, i - 1 - t);
            C1.Mod(a[i], 1);
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    context-annotation
    bean-annotation
    K-means算法
    基于概率的分类-贝叶斯分类
    Application
    ConfigurableApplicationContext
    相关性分析
    方差分析
    Java 大写金额转换成数字
    linux 遍历文件添加index
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/13794230.html
Copyright © 2011-2022 走看看