The 18th Zhejiang Provincial Collegiate Programming Contest部分题解(A,C,G,J,L,M)

A. League of Legends

Codeforces

题意

签到题

C. Cube

Codeforces

题意

给出 8 8 8 个点,判断这 8 8 8 个点是否组成一个正方体。

题解

8 8 8 个点两两组对得 28 28 28 条边,判断这 28 28 28 条边是否有 12 12 12 个相等的 A A A (楞长), 12 12 12 个相等的 B B B (正方形的对角线), 4 4 4 个相等的 C C C (正方体的对角线),且 A 2 + B 2 = C 2 A^2+B^2=C^2 A2+B2=C2 。若是,则是正方体,否则不是。

代码

#include 
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

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

struct poi {
    int x, y, z;
    poi(){}
    poi(int x, int y, int z):x(x), y(y), z(z) {}
    void sc() {
        x = read(), y = read(), z = read();
    }
    bool operator<(const poi b) const {
        if(x != b.x) return x < b.x;
        if(y != b.y) return y < b.y;
        if(z != b.z) return z < b.z;
        return 0;
    }
};

int T;
vector<poi> a;

LL getDis(poi a, poi b) {
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z);
}

int sol() {
    _for(i, 8) _for(j, i) if(!(a[i] < a[j]) && !(a[j] < a[i])) return 0;
    vector<LL> diss;
    _for(i, 8) _for(j, i) diss.push_back(getDis(a[i], a[j]));
    sort(diss.begin(), diss.end());
    _for(i, 12) _for(j, i) if(diss[i] != diss[j]) return 0;
    _for(i, 12) _for(j, i) if(diss[12 + i] != diss[12 + j]) return 0;
    _for(i, 4) _for(j, i) if(diss[24 + i] != diss[24 + j]) return 0;
    if(diss[0] + diss[12] != diss[24]) return 0;
    return 1;
}

int main() {
    // freopen("in.txt", "r", stdin);
    scanf("%d", &T);
    _for(i, T) {
        a.resize(8);
        _for(i, 8) a[i].sc();
        printf("%s\n", sol() ? "YES":"NO");
    }
    return 0;
}

G. Wall Game

Codeforces

题意

给出一个蜂窝状的地图。有 n n n 轮,两种操作。

  1. 选出一个格子,并和周围曾经选过的格子联通起来。
  2. 输出一个格子所在的连通块的最外层边的个数。

题解

先把每个格子映射成一个编号,之后就可以利用编号维护并查集。

维护连通块的大小和连通块内共享的边的个数。

选出格子时,查看周围一圈曾经选过的格子,使他的祖先指向此回合所选的格子,并更新连通块大小和连通块内共享的边的个数。

计算格子时,输出连通块 s i z e ∗ 6   − size* 6\ - size6  共享的边 ∗ 2 *2 2 即可。

代码

#pragma GCC optimize(3, "Ofast", "inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include 
#define getchar() (S == T && (T = (S = BB) + fread(BB, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
char BB[1 << 20], *S = BB, *T = BB;
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for (int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for (int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if (debug)
#define nl(i, n) (i == n - 1 ? "\n" : " ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 500005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

inline LL read() {
    LL x(0), 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 - '0'; ch = getchar(); }
    return x * f;
}

struct poi {
    int x, y;
    poi(){}
    poi(int x, int y):x(x), y(y) {}
    bool operator<(const poi &b) const {
        if(x != b.x) return x < b.x;
        else return y < b.y;
    }
};

struct ope {
    int op, x, y;
    ope(){}
    ope(int op, int x, int y):op(op), x(x), y(y) {}
};

map< poi, int > toNum;
// map< int, poi > toPoi;
int f[maxn];
vector<ope> opes;
int n;
int cnt;
int num[maxn], wal[maxn];
map<poi, int> vis;
int dir[6][2] = {0, 1, 1, 0, 0, -1, -1, 0, -1, 1, 1, -1};

void init() {
}

int find(int x) {
    return x == f[x] ? x : f[x] = find(f[x]);
}

void sol() {
    init();
    _for(i, n) {
        int op = read(), x = read(), y = read();
        opes.push_back(ope(op, x, y));
        poi p = poi(x, y);
        if(!toNum.count(p)) toNum[p] = cnt++;
    }
    dg for(auto i : toNum) printf("%d\t%d:\t%d\n", i.first.x, i.first.y, i.second);
    _for(i, cnt) f[i] = i;
    for(ope i : opes) {
        poi now = poi(i.x, i.y);
        int nowId = toNum[now];
        if(i.op == 1) {
            vis[now] = 1;
            ++num[nowId];
            _for(k, 6) {
                int x = i.x + dir[k][0], y = i.y + dir[k][1];
                poi tar = poi(x, y);
                if(!vis.count(tar)) continue;
                int tarId = toNum[tar];
                if(find(nowId) != find(tarId)) {
                    num[nowId] += num[find(tarId)];
                    wal[nowId] += wal[find(tarId)];
                    f[find(tarId)] = nowId;
                }
                ++wal[nowId];
            }
            dg printf("x,y:(%d,%d)\tnum:%d\twal:%d\n", i.x, i.y, num[nowId], wal[nowId]);
        }
        else {
            int der = find(nowId);
            dg outval(der);
            printf("%d\n", num[der] * 6 - wal[der] * 2);
        }
    }
}

int main() {
    // ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    time_t beg, end;
    if (debug) beg = clock();

    n = read();
    sol();

    if (debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    return 0;
}

J. Grammy and Jewelry

Codeforces

题意

n n n 个地点由 m m m 条边相连,第 i i i 个个地点有价值 a [ i ] a[i] a[i] 的宝藏,初始时主角 V V V 在编号为 1 1 1 的地点,他拿到第 i i i 个地点的宝藏花费的时间是 d i s ( 1 , i ) ∗ 2 dis(1,i)*2 dis(1,i)2

分别计算出 [ 1 , T ] [1,T] [1,T] 时间内 V V V 能拿到的宝藏价值之和。

注意有自环和重边。

题解

对编号 1 1 1 求最短路,之后多重背包求解最大值,背包大小为 T T T,然后一次输出 d p dp dp 数组即可。

代码

#include 
#define _for(i, a) for (int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for (int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f
const int N = 3007;
using namespace std;

LL read() {
    LL x(0), f(1);
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
vector<int> G[N];
int a[N];
int dis[N];
int vis[N];
int dp[N];
struct node {
    int u, w;
    friend bool operator<(node a, node b) { return a.w > b.w; }
};
int n, m, T;
void Dijkstra() {
    priority_queue<node> q;
    _rep(i, 1, n) dis[i] = 0x3f3f3f3f;
    q.push(node{1, 0});
    dis[1] = 0;
    memset(vis, 0, sizeof vis);
    while (!q.empty()) {
        node t = q.top();
        q.pop();
        vis[t.u] = 1;
        int u = t.u;
        int w = t.w;
        for (auto v : G[u]) {
            if (!vis[v] && dis[v] > w + 1) {
                dis[v] = w + 1;
                q.push(node{v, dis[v]});
            }
        }
    }
}
int main() {
    n = read(), m = read(), T = read();
    _rep(i, 2, n) a[i] = read();
    _rep(i, 1, m) {
        int u = read(), v = read();
        if (u == v) continue;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    Dijkstra();
    _rep(i, 1, n) {
        for (int j = dis[i] * 2; j <= T; ++j) {
            dp[j] = max(dp[j], dp[j - dis[i] * 2] + a[i]);
        }
    }
    _rep(i, 1, T) printf("%d%s", dp[i], (i == T ? "\n" : " "));
    return 0;
}

L. String Freshman

Codeforces

题意

题意貌似出锅了,本来应该是签到题的。

题解

判断第 1 1 1 个字母是否重复出现即可。

M. Game Theory

Codeforces

题意

A A A B B B 玩游戏,游戏一共有 n n n 个回合,每回合 A A A 随机选出一个 [ 1 , 20 ] [1,20] [1,20] 的数字 x x x B B B 采取最优策略,在不知道 A A A 选的数字的情况下选出一个 [ 1 , 20 ] [1,20] [1,20] 的数字 y y y

每回合执行以下操作:

  1. 角色 B B B A A A 手里获得 x x x 点分数。
  2. 角色 A A A B B B 手里获得 y y y 点分数。
  3. x > y x>y x>y 时,角色 A A A B B B 手里获得额外的 10 10 10 点分数。
  4. x < y xx<y 时,角色 B B B A A A 手里获得额外的 10 10 10 点分数。

输出 A A A 能获得的分数的期望值。

题解

由于每回合之间互不影响,所以可以先算出一个回合的得分期望值,然后乘以 n n n 即可。

枚举 B B B 的所有选择,每个选择可以算出一个得分期望值,从中选出一个最大的作为 B B B 的每回合的选择。

计算后发现无论 B B B 怎么选,得分期望都是 0 0 0 。所以答案就是0.0000。直接输出即可。

你可能感兴趣的:(#,高级数据结构,★,ACM,★,c语言,算法,c++)