2012 Multi-University #7

最短路+拆点 A As long as Binbin loves Sangsang

题意:从1走到n,每次都是LOVE,问到n时路径是连续多个"LOVE"的最短距离.秀恩爱不想吐槽.

分析:在普通的最短路上有寻路的限制,把一个点看成4个点,表示通过某一个字符到该点的最短距离.注意自环的处理,还有距离会爆int。

#include <bits/stdc++.h>

const int N = 1314 + 5;
const int M = 13520 + 5;
const long long INF = 200000000000LL;
struct Edge {
    int v, w, ch, nex;
};
Edge edge[M<<1];
int head[N];
int n, m, etot;

void init_edge() {
    etot = 0;
    memset (head, -1, sizeof (head));
}

void add_edge(int u, int v, int w, char ch) {
    edge[etot].v = v; edge[etot].w = w;
    edge[etot].nex = head[u];
    if (ch == 'L') {
        edge[etot].ch = 0;
    } else if (ch == 'O') {
        edge[etot].ch = 1;
    } else if (ch == 'V') {
        edge[etot].ch = 2;
    } else if (ch == 'E') {
        edge[etot].ch = 3;
    }
    head[u] = etot++;
}

struct Node {
    int u, id;
};
long long dis[N][4];
int cnt[N][4];
bool vis[N][4];

void SPFA(int s) {
    for (int i=1; i<=n; ++i) {
        for (int j=0; j<4; ++j) {
            vis[i][j] = false;
            dis[i][j] = INF;
            cnt[i][j] = 0;
        }
    }
    dis[s][3] = 0; vis[s][3] = true;
    std::queue<Node> que;
    que.push ((Node) {s, 3});
    while (!que.empty ()) {
        Node now = que.front (); que.pop ();
        int u = now.u, id = now.id;
        vis[u][id] = false;
        for (int i=head[u]; ~i; i=edge[i].nex) {
            Edge &e = edge[i];
            if (e.ch != (id + 1) % 4) {
                continue;
            }
            if (dis[e.v][e.ch] > dis[u][id] + e.w || dis[e.v][e.ch] == 0) {
                dis[e.v][e.ch] = dis[u][id] + e.w;
                cnt[e.v][e.ch] = cnt[u][id];
                if (e.ch == 3) {
                    cnt[e.v][e.ch]++;
                }
                if (!vis[e.v][e.ch]) {
                    vis[e.v][e.ch] = true;
                    que.push ((Node) {e.v, e.ch});
                }
            } else if ((dis[e.v][e.ch] == dis[u][id] + e.w || dis[e.v][e.ch] == 0) && cnt[e.v][e.ch] <= cnt[u][id]) {
                cnt[e.v][e.ch] = cnt[u][id];
                if (e.ch == 3) {
                    cnt[e.v][e.ch]++;
                }
                if (!vis[e.v][e.ch]) {
                    vis[e.v][e.ch] = true;
                    que.push ((Node) {e.v, e.ch});
                }
            }
        }
    }
}

int main() {
    int T;
    scanf ("%d", &T);
    for (int cas=1; cas<=T; ++cas) {
        init_edge ();
        scanf ("%d%d", &n, &m);
        char ch[2];
        for (int i=0; i<m; ++i) {
            int u, v, l;
            scanf ("%d%d%d%s", &u, &v, &l, ch);
            add_edge (u, v, l, ch[0]);
            add_edge (v, u, l, ch[0]);
        }
        SPFA (1);
        if (dis[n][3] == INF || cnt[n][3] == 0) {
            printf ("Case %d: Binbin you disappoint Sangsang again, damn it!
", cas);
        } else {
            printf ("Case %d: Cute Sangsang, Binbin will come with a donkey after travelling %I64d meters and finding %d LOVE strings at last.
", cas, dis[n][3], cnt[n][3]);
        }
    }
    return 0;
}

DP+优化 C Dragon Ball

题意:m个时间,每个时间去取一个龙珠,代价是距离|x-ball[i].pos|,此时人移动到龙珠的位置,还有该龙珠的代价ball[i].cost,问最小代价。

分析:,另一种情况同理,先对每个时间的位置排序,求i-1时间前缀最小的转移就好了。

#include <bits/stdc++.h>

const int N = 50 + 5;
const int M = 1000 + 5;
const int INF = 0x3f3f3f3f;
struct Ball {
    int pos, cost;
    bool operator < (const Ball &rhs) const {
        return pos < rhs.pos;
    }
};
Ball ball[N][M];
int dp[N][M];
int m, n, x;

int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        scanf ("%d%d%d", &m, &n, &x);
        for (int i=1; i<=m; ++i) {
            for (int j=1; j<=n; ++j) {
                scanf ("%d", &ball[i][j].pos);
            }
        }
        for (int i=1; i<=m; ++i) {
            for (int j=1; j<=n; ++j) {
                scanf ("%d", &ball[i][j].cost);
            }
            std::sort (ball[i]+1, ball[i]+1+n);
        }
        memset (dp, INF, sizeof (dp));
        for (int i=1; i<=n; ++i) {
            dp[1][i] = abs (ball[1][i].pos - x) + ball[1][i].cost;
        }
        for (int i=2; i<=m; ++i) {
            int k = 1, mn = INF;
            for (int j=1; j<=n; ++j) {
                for (; k<=n && ball[i-1][k].pos <= ball[i][j].pos; ++k) {
                    mn = std::min (mn, dp[i-1][k] - ball[i-1][k].pos);
                }
                dp[i][j] = mn + ball[i][j].pos + ball[i][j].cost;
            }
            k = n; mn = INF;
            for (int j=n; j>=1; --j) {
                for (; k>=1 && ball[i-1][k].pos > ball[i][j].pos; --k) {
                    mn = std::min (mn, dp[i-1][k] + ball[i-1][k].pos);
                }
                dp[i][j] = std::min (dp[i][j], mn - ball[i][j].pos + ball[i][j].cost);
            }
        }
        int ans = INF;
        for (int i=1; i<=n; ++i) {
            ans = std::min (ans, dp[m][i]);
        }
        printf ("%d
", ans);
    }
    return 0;
}

模拟 E Matrix operation

读懂题,照着模拟

#include <bits/stdc++.h>

int mat[4][4] = {2, 3, 1, 1,
                 1, 2, 3, 1,
                 1, 1, 2, 3,
                 3, 1, 1, 2};
int a[4][4], tmp[4];

void run() {
    int ans[4][4];
    for (int i=0; i<4; ++i) {
        for (int j=0; j<4; ++j) {
            for (int k=0; k<4; ++k) {
                int t;
                if (mat[i][k] == 2) {
                    t = a[k][j] << 1;
                    if (t > 0xFF) {
                        t ^= 0x1B;
                    }
                    if (t > 0xFF) {
                        t %= (0xFF + 1);
                    }
                } else if (mat[i][k] == 3) {
                    t = a[k][j] << 1;
                    if (t > 0xFF) {
                        t ^= 0x1B;
                    }
                    t ^= a[k][j];
                    if (t > 0xFF) {
                        t %= (0xFF + 1);
                    }
                } else {
                    t = a[k][j];
                }
                tmp[k] = t;
            }
            int t = tmp[0];
            for (int i=1; i<4; ++i) {
                t ^= tmp[i];
            }
            ans[i][j] = t;
        }
    }
    for (int i=0; i<4; ++i) {
        for (int j=0; j<3; ++j) {
            printf ("%02X ", ans[i][j]);
        }
        printf ("%02X
", ans[i][3]);
    }
}

int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        for (int i=0; i<4; ++i) {
            for (int j=0; j<4; ++j) {
                scanf ("%X", &a[i][j]);
            }
        }
        run ();
        if (T) {
            puts ("");
        }
    }
    return 0;
}

数学+快速幂 F Palindrome graph

题意:一个n*n的图填充颜色使得图如何反转或旋转都不会变化。

分析:考虑到是中心对称的,只要考虑1/8的图(三角形)就行了,假设总和x个。填充过的颜色的位置转移到1/8的图中(假设y个),其他的地方能涂k种颜色,答案是k^(x-y)。

#include <bits/stdc++.h>

const int MOD = 100000007;

int pow_mod(int x, int n) {
    int ret = 1;
    while (n) {
        if (n & 1) {
            ret = (long long) ret * x % MOD;
        }
        x = (long long) x * x % MOD;
        n >>= 1;
    }
    return ret;
}

const int N = 10005;

bool vis[N/2][N/2];
int n, m, k;

int main() {
    while (scanf ("%d%d%d", &n, &m, &k) == 3) {
        memset (vis, false, sizeof (vis));
        int mid = n / 2;
        if (n & 1) {
            mid++;
        }
        for (int i=0; i<m; ++i) {
            int x, y;
            scanf ("%d%d", &x, &y);
            x++; y++;
            if (x > mid) {
                x = n + 1 - x;
            }
            if (y > mid) {
                y = n + 1 - y;
            }
            if (x < y) {
                std::swap (x, y);
            }
            vis[x][y] = true;
        }
        int c = 0;
        for (int i=1; i<=mid; ++i) {
            for (int j=1; j<=i; ++j) {
                if (!vis[i][j]) {
                    c++;
                }
            }
        }
        printf ("%d
", pow_mod (k, c));
    }
    return 0;
}

DFS序+线段树 G Successor

题意:给了n个人的上下级关系,每个人有能力和忠诚度,问如果上级被炒了,下属里能力比他强,忠诚度最高的是谁。

分析:其实就是给了一棵树,DFS序转换为线性序列,每一个上级管辖一段区间,按照能力从大到小排序,每次插入能力比上级强的,相同的也同时插入,询问忠诚度最高的对应人的id即是答案。

#include <bits/stdc++.h>

const int N = 5e4 + 5;
struct Person {
    int sup, loy, ab, id;
    bool operator < (const Person &rhs) const {
        return ab > rhs.ab;
    }
}p[N];
int n, m;
int left[N], right[N];
std::map<int, int> ID;
std::vector<int> edge[N];
int tot;

#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1

int mx[(N<<1)<<2];
void push_up(int o) {
    mx[o] = std::max (mx[o<<1], mx[o<<1|1]);
}

void updata(int p, int v, int l, int r, int o) {
    if (l == r) {
        mx[o] = v;
        return ;
    }
    int mid = l + r >> 1;
    if (p <= mid) {
        updata (p, v, lson);
    } else {
        updata (p, v, rson);
    }
    push_up (o);
}

int query(int ql, int qr, int l, int r, int o) {
    if (ql <= l && r <= qr) {
        return mx[o];
    }
    int mid = l + r >> 1, ret = -1;
    if (ql <= mid) {
        ret = std::max (ret, query (ql, qr, lson));
    }
    if (qr > mid) {
        ret = std::max (ret, query (ql, qr, rson));
    }
    return ret;
}

void DFS(int u) {
    left[u] = tot++;
    for (auto v: edge[u]) {
        DFS (v);
    }
    right[u] = tot;
}

int ans[N];

void solve() {
    tot = 1;
    DFS (0);
    //build (1, tot-1, 1);
    memset (mx, -1, sizeof (mx));
    std::sort (p+1, p+n);
    ans[0] = -1;
    for (int j, i=1; i<n; i=j) {
        j = i;
        while (j < n && p[j].ab == p[i].ab) {
            int id = p[j].id;
            ans[id] = ID[query (left[id]+1, right[id]-1, 1, tot-1, 1)];
            j++;
        }
        j = i;
        while (j < n && p[j].ab == p[i].ab) {
            int id = p[j].id;
            updata (left[id], p[j].loy, 1, tot-1, 1);
            j++;
        }
    }
}

int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        scanf ("%d%d", &n, &m);
        for (int i=0; i<n; ++i) {
            edge[i].clear ();
        }
        ID.clear ();
        ID[-1] = -1;
        for (int i=1; i<n; ++i) {
            scanf ("%d%d%d", &p[i].sup, &p[i].loy, &p[i].ab);
            p[i].id = i;
            edge[p[i].sup].push_back (i);
            ID[p[i].loy] = i;
        }
        solve ();
        for (int i=0; i<m; ++i) {
            int j;
            scanf ("%d", &j);
            printf ("%d
", ans[j]);
        }        
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Running-Time/p/5509539.html