CCPC-Wannafly Summer Camp 2019 Day1

 

A - Jzzhu and Cities

CodeForces - 449B

题意:n座城市,m条路,k条铁路啥的吧,然后要求最多能删多少条铁路保持1到$n$的最短路不变。

思路:因为铁路是从1出发的。所以能删的铁路有该铁路长度不等于1到该节点的最短路的,相等的时候,如果该节点的入度非1,也可以删去。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <functional>
#define ll long long
#define pb push_back
#define P pair<ll, int>
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;
vector<P> G[N];
bool done[N];
struct Po { int v; ll c; } po[N];
int n, m, k;
int in[N];
ll d[N];

void dijkstra(ll *d, int s) {
    for (int i = 1; i <= n; i++) d[i] = INF, done[i] = 0;
    d[s] = 0;
    priority_queue<P, vector<P>, greater<P> > que;
    que.push(P(0, s));
    while (!que.empty()) {
        auto p = que.top(); que.pop();
        int u = p.second;
        if (done[u]) continue;
        done[u] = 1;
        for (auto pp: G[u]) {
            int v = pp.second;
            if (d[v] > d[u] + pp.first) {
                in[v] = 1;
                d[v] = d[u] + pp.first;
                que.push(P(d[v], v));
            } else if (d[v] == d[u] + pp.first) {
                in[v]++;
            }
        }
    }
}

int main() {
    read(n); read(m); read(k);
    while (m--) {
        int u, v; ll c;
        read(u); read(v); read(c);
        G[u].pb(P(c, v));
        G[v].pb(P(c, u));
    }
    for (int i = 1; i <= k; i++) {
        read(po[i].v); read(po[i].c);
        G[1].pb(P(po[i].c, po[i].v));
        G[po[i].v].pb(P(po[i].c, 1));
    }
    dijkstra(d, 1);
    memset(done, 0, sizeof(done));
    int ans = 0;
    for (int i = 1; i <= k; i++) {
        int v = po[i].v;
        if (d[v] < po[i].c) ans++;
        else if (d[v] == po[i].c && in[v] > 1) {
            in[v]--;
            ans++;
        }
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

B - Phillip and Trains

CodeForces - 585B

题意:$3 \times n$的方格,一个人在最左边的一个起始位置,先向右走一步,再选择向上、不动、向下走一步。然后轮到所有火车往左走两步。问这个人能否安全走到最右边那列。

思路:BFS。当前位置先往右走一步,再枚举上中下三个位置,因为火车向左走两步,可以等同于人往右走两步,所以就是判断人能不能往后走两格。

#include <cstdio>
#include <algorithm>
#include <cctype>
#include <queue>
#include <cstring>
#define P pair<int, int>
using namespace std;

const int N = 110;
int n, k;
char s[5][N];
bool ans;
bool mp[5][N];

bool bfs(int sx) {
    queue<pair<int, int> > que;
    que.push(P(sx, 1));
    while (!que.empty()) {
        P p = que.front(); que.pop();
        int x = p.first, y = p.second;
        if (isalpha(s[x][++y])) continue;
        if (y >= n) return true;
        for (int i = -1; i <= 1; i++) {
            int dx = x + i;
            if (dx <= 0 || dx > 3) continue;
            if (isalpha(s[dx][y]) || isalpha(s[dx][y + 1]) || isalpha(s[dx][y + 2]) || s[dx][y + 2] == 1) continue;
            int dy = y + 2;
            if (dy >= n) return true;
            s[dx][dy] = 1;
            que.push(P(dx, dy));
        }
    }
    return false;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &k);
        memset(s, 0, sizeof(s));
        for (int i = 1; i <= 3; i++) scanf("%s", s[i] + 1);
        int sx = 0;
        for (int i = 1; i <= 3; i++)
                if (s[i][1] == 's') 
                    sx = i;
        if (bfs(sx)) puts("YES");
        else puts("NO");
    }
    return 0;
}
View Code

 

C - A Mist of Florescence

CodeForces - 989C

借鉴的别人的思路。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

char s[55][55];

int main() {
    int a, b, c, d;
    scanf("%d%d%d%d", &a, &b, &c, &d);
    a--; b--;
    for (int i = 0; i < 50; i++)
        for (int j = 0; j < 50; j++) 
            if (i < 25) s[i][j] = 'A';
            else s[i][j] = 'B';
    for (int i = 0; i < 24; i += 2)
        for (int j = 0; j < 50; j += 2) {
            if (b) s[i][j] = 'B', b--;
            else if (d) s[i][j] = 'D', d--;
        }
    for (int i = 26; i < 50; i += 2)
        for (int j = 0; j < 50; j += 2) {
            if (a) s[i][j] = 'A', a--;
            else if (c) s[i][j] = 'C', c--;
        }
    printf("50 50\n");
    for (int i = 0; i < 50; i++) puts(s[i]);
    return 0;
}
View Code

 

D - Unbearable Controversy of Being

CodeForces - 489D

题意:给一个有向图,找出$\left( a,b,c,d\right)$的对数满足题面的图。

思路:暴力枚举$a$,$c$然后组合数搞搞。

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 3031;
bool mp[N][N];
vector<int> G[N];

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

int main() {
    //freopen("in.txt", "r", stdin);
    int n, m;
    read(n); read(m);
    while (m--) {
        int u, v;
        read(u); read(v);
        mp[u][v] = 1;
        G[u].push_back(v);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j) {
                int res = 0;
                for (auto temp: G[i])
                    if (temp != i && temp != j && mp[temp][j]) res++; 
                ans += res * (res - 1) / 2;
            }
    printf("%d\n", ans);
    return 0;
}

/*
input
5 4
1 2
2 3
1 4
4 3
output
1
input
4 12
1 2
1 3
1 4
2 1
2 3
2 4
3 1
3 2
3 4
4 1
4 2
4 3
output
12
*/
View Code

 

E - Igor In the Museum

CodeForces - 598D

#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
#define P pair<int, int>
using namespace std;

const int N = 1010;
bool vis[N][N];
int cnt, n, m;
int ans[N * N];
int mp[N][N];
char mpp[N][N];
const int dir[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

void dfs(int x, int y, int now) {
    vis[x][y] = 1;
    mp[x][y] = now;
    for (int i = 0; i < 4; i++) {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if (dx <= 0 || dy <= 0 || dx > n || dy > m) continue;
        if (!vis[dx][dy]) {
            if (mpp[dx][dy] == '*') ans[now]++;
            else dfs(dx, dy, now);
        }
    }
}

int main() {
    int k;
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) scanf("%s", mpp[i] + 1);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (mpp[i][j] == '.' && !vis[i][j]) {
                dfs(i, j, ++cnt);
            }
        }  
    while (k--) {
        int x, y;
        scanf("%d%d", &x, &y);
        printf("%d\n", ans[mp[x][y]]);
    }
    return 0;
}
View Code

 

F - The Child and Toy

CodeForces - 437C

贪心优先处理权值大的。只考虑两个的情况,优先处理一个会使答案加上另一个的权值,所以先处理大的会比处理小的更优。这个能推广到多个数。

#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 1010;
struct P { 
    ll v; int u;
    bool operator < (const P &rhs) const {
        return v > rhs.v;
    }
} p[N];
int n, a[N], m;
bool vis[N];
vector<int> G[N];

int main() {
    read(n); read(m);
    for (int i = 1; i <= n; i++) {
        read(a[i]);
        p[i].u = i; p[i].v = a[i];
    }
    while (m--) {
        int u, v;
        read(u); read(v);
        G[u].pb(v); G[v].pb(u);
    }
    sort(p + 1, p + n + 1);
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        int u = p[i].u;
        vis[u] = 1;
        for (auto v: G[u]) 
            if (!vis[v]) ans += a[v];
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

G - New Year Permutation

CodeForces - 500B

题意:给一个排列,以及代表哪些位置能交换的矩阵,问字典序最小的排列长啥样。

思路:现在一想不就是Floyd传递闭包吗。写的时候没想起来,就dfs处理一下连通块之类的。然后就可以贪心去排了

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 330;
int pos[N], a[N];
char s[N][N];
int mp[N][N];
int block[N], n, cnt;

void dfs(int u, int c) {
    //printf("%d %d\n", u, c);
    block[u] = c;
    for (int i = 1; i <= n; i++) {
        if (s[u][i] == '1' && !block[i]) {
            dfs(i, c);
        }
    }
}

int main() {
    //freopen("in.txt", "r", stdin);
    read(n);
    for (int i = 1; i <= n; i++) {
        read(a[i]);
        pos[a[i]] = i;
    }
    for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
    for (int i = 1; i <= n; i++) 
        if (!block[i]) dfs(i, ++cnt);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            mp[i][j] = (block[i] == block[j]) ? 1 : 0;
        }
    }
    for (int i = n; i > 1; i--) {
        for (int j = n; j > pos[i]; j--) {
            if (mp[pos[i]][j] && a[j] < i) {
                //printf("%d %d\n", pos[i], j);
                int temp = a[j];
                swap(a[pos[i]], a[j]);
                swap(pos[i], pos[temp]);
                break;
            }
        }
    }
    for (int i = 1; i <= n; i++) printf("%d%c", a[i], " \n"[i == n]);
    return 0;
}

/*
input
7
5 2 4 3 6 7 1
0001001
0000000
0000010
1000001
0000000
0010000
1001000
output
1 2 4 3 6 7 5
input
5
4 2 1 5 3
00100
00011
10010
01101
01010
output
1 2 3 4 5
*/
View Code

 

H - Alyona and the Tree

CodeForces - 682C

题意:给一棵树,如果存在一个叶子到它的一个祖先的距离大于它的权值,则该叶子应该删去,问最少需要删多少节点。

思路:两遍dfs,第一次处理出每个节点子树的节点数、该节点到1的距离$d$和从1到该节点的前缀距离中的最小值$mn$,$d-mn$能得到该节点到所有祖先中的最大距离,然后在dfs判断当前该节点是否要删即可。

#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
#define P pair<int, ll>
#define pb push_back
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 1e5 + 7;
ll dis[N], a[N], mm[N];
int n, sz[N], ans;
vector<P> G[N];

void dfs1(int u, int pre) {
    sz[u] = 1;
    for (int i = 0; i < G[u].size(); i++) {
        P p = G[u][i];
        if (p.first == pre) continue;
        dis[p.first] = dis[u] + p.second;
        mm[p.first] = min(mm[u], dis[p.first]);
        dfs1(p.first, u);
        sz[u] += sz[p.first];
    }    
}

void dfs2(int u, int pre) {
    for (int i = 0; i < G[u].size(); i++) {
        P p = G[u][i];
        if (p.first == pre) continue;
        if (dis[p.first] - mm[p.first] > a[p.first]) {
            ans += sz[p.first];
            continue;
        }
        dfs2(p.first, u);
    }
}

int main() {
    read(n);
    for (int i = 1; i <= n; i++) read(a[i]);
    for (int i = 2; i <= n; i++) {
        int u; ll c;
        read(u); read(c);
        G[u].pb(P(i, c));
        G[i].pb(P(u, c));
    }
    dfs1(1, 1);
    dfs2(1, 1);
    printf("%d\n", ans);
}
View Code

 

I - Network Safety

CodeForces - 1039C

 思路自https://www.cnblogs.com/DeaphetS/p/9599587.html

 

J - Resort

CodeForces - 350B

思路:写了个类似于记忆化的东西,懒得想太多了。

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 1e5 + 10;
int dp[N], a[N], to[N];
bool is[N];
int top, st[N], out[N];
vector<int> G[N];

int DP(int u) {
    if (dp[u] != -1) return dp[u];
    int &ans = dp[u];
    ans = 1;
    int v = to[u];
    if (v && !is[v] && out[v] == 1) ans = DP(v) + 1;
    return ans;
}

int main() {
    //freopen("in.txt", "r", stdin);
    memset(dp, -1, sizeof(dp));
    int n;
    read(n);
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        int x; read(x);
        if (x) a[++cnt] = i, is[i] = 1;
    }
    //for (int i = 1; i <= cnt; i++) printf("%d%c", a[i], " \n"[i == cnt]);
    for (int i = 1; i <= n; i++) {
        int x; read(x);
        if (!x) continue;
        out[x]++;
        to[i] = x;
    }
    int ans = 0, id = 0;
    for (int i = 1; i <= cnt; i++) {
        int res = DP(a[i]);
        if (res > ans) {
            id = a[i];
            ans = res;
        }
    }
    printf("%d\n", ans);
    st[++top] = id;
    id = to[id];
    for (; id && !is[id] && out[id] == 1; id = to[id]) st[++top] = id;
    while(top) printf("%d%c", st[top], " \n"[top == 1]), --top;
}

/*

Input
5
0 0 0 0 1
0 1 2 3 4
Output
5
1 2 3 4 5
Input
5
0 0 1 0 1
0 1 2 2 4
Output
2
4 5
Input
4
1 0 0 0
2 3 4 2
Output
1
1
*/
View Code

 

K - Royal Questions

CodeForces - 875

题意:王子和公主的二分图匹配,求最大收

思路:数据范围小可以二分图匹配搞搞,但是这数据范围太大了。注意到一个公主与两个王子连边的权值是一样大的,就可以不考虑这个公主了,只考虑两个王子之间有一条边。

魔改一下kruskal,边按权值从大到小排序,只有当两个点都被选中过的时候,才不能继续选,两个点在一个并查集里同理。

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 2e5 + 10;

struct E {
    int a, b, w;
    bool operator < (const E &rhs) const {
        return w > rhs.w;
    }
} e[N];

int fa[N], p[N];

int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }

int main() {
    //freopen("in.txt", "r", stdin);
    int n, m;
    read(n); read(m);
    for (int i = 1; i <= m; i++) {
        read(e[i].a);
        read(e[i].b);
        read(e[i].w);
    }
    sort(e + 1, e + m + 1);
    for (int i = 1; i <= n; i++) fa[i] = i;
    int ans = 0;
    for (int i = 1; i <= m; i++) {
        int x = getfa(e[i].a), y = getfa(e[i].b);
        if (x != y) {
            if (p[x] && p[y]) continue;
            p[x] = p[x] | p[y];
            fa[y] = x;
            ans += e[i].w;
        } else if (!p[x]) {
            p[x] = 1;
            ans += e[i].w;
        }
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

L - Love Triangle

CodeForces - 939A

#include <cstdio>
#include <vector>
#include <queue>
#define eb emplace_back
using namespace std;

const int N = 5050;
int to[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x; scanf("%d", &x);
        to[i] = x;
    }
    for (int i = 1; i <= n; i++) {
        if (to[to[to[i]]] == i) {
            puts("YES");
            return 0;
        }
    }
    puts("NO");
    return 0;
}
View Code

 

M - Bakery

CodeForces - 707B

题意:$n$座城市,$m$条边,$k$个关键点,问能否找一个非关键点和一个关键点,它们之间的距离最小。

思路:刚开始以为要$k$次最短路???过一会才意识过来,这个最小距离只能是题目给的边。然后找一下就OK了。

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
bool pos[N];
struct P { int u, v, c; } p[N];

int main() {
    int n, m, k;
    read(n); read(m); read(k);
    for (int i = 1; i <= m; i++) {
        read(p[i].u); read(p[i].v); read(p[i].c);
    }
    for (int i = 1; i <= k; i++) {
        int x; read(x);
        pos[x] = 1;
    }
    int ans = INF;
    for (int i = 1; i <= m; i++) 
        if (pos[p[i].u] + pos[p[i].v] == 1) ans = min(ans, p[i].c);
    if (ans == INF) ans = -1;
    printf("%d\n", ans);
    return 0;
}
View Code

 

N - News Distribution

CodeForces - 1167C

思路:又是一道被我误伤成dfs的题,但貌似我的代码跑得更快?hhh

#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;

const int N = 1e6 + 10;
vector<int> G[N];
int vis[N], cnt, ans[N], n;

void dfs(int u) {
    vis[u] = cnt;
    if (u <= n) ans[cnt]++;
    for (auto v: G[u]) {
        if (!vis[v]) {
            dfs(v);
        }
    }
}

int main() {
    int m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int k; scanf("%d", &k);
        while (k--) {
            int x;
            scanf("%d", &x);
            G[x].pb(i + n);
            G[i + n].pb(x);
        }
    }
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
              cnt++;
              dfs(i);
        }
        printf("%d%c", ans[vis[i]], " \n"[i == n]);
    }
    return 0;
}
View Code

 

O - NP-Hard Problem

CodeForces - 687A

思路:二分图染色

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define eb emplace_back
using namespace std;

template<typename T>
inline void read(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    x *= f;    
}

const int N = 1e5 + 7;
int n, m, color[N];
vector<int> G[N], ans[2];

bool dfs(int u, int c) {
    color[u] = c;
    ans[c == 1].eb(u);
    for (auto v: G[u]) {
        if (!color[v] && !dfs(v, -c)) return false;
        else if (color[v] == color[u]) return false;
    }
    return true;
}

int main() {
    read(n); read(m);
    while (m--) {
        int u, v;
        read(u); read(v);
        G[u].eb(v); G[v].eb(u);
    }
    bool res = 1;
    for (int i = 1; i <= n; i++) {
        if (!color[i]) {
            res = dfs(i, 1);
            if (!res) {
                puts("-1");
                return 0;
            }
        }
    }
    int sz = ans[1].size();
    printf("%d\n", sz);
    for (int i = 0; i < sz; i++) printf("%d%c", ans[1][i], " \n"[i == sz - 1]);
    sz = ans[0].size();
    printf("%d\n", sz);
    for (int i = 0; i < sz; i++) printf("%d%c", ans[0][i], " \n"[i == sz - 1]);
    return 0;
}
View Code

 

posted @ 2019-07-24 00:01  Mrzdtz220  阅读(279)  评论(0编辑  收藏  举报