The 18th Zhejiang Provincial Collegiate Programming Contest 补题记录(ACFGJLM)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The 18th Zhejiang Provincial Collegiate Programming Contest 补题记录(ACFGJLM)相关的知识,希望对你有一定的参考价值。

补题链接:Here

A. League of Legends

签到题,求和判断即可

ll suma, sumb;
void solve() {
    ll x;
    for (int i = 1; i <= 5; ++i)cin >> x, suma += x;
    for (int i = 1; i <= 5; ++i)cin >> x, sumb += x;
    if (suma < sumb) cout << "Red\\n"; // 注意这里要写suma<sumb
    else cout << "Blue\\n";
}

C. Cube

给定 8 个点(三维XYZ),判断是否是正方体


判断是否有 12 个相等的棱, 12 个相等的面对角线,4 个相等的体对角线,以及棱,面对角线和体对角线可以形成直角三角形(满足勾股定理)就行了。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct Point {
    int x, y, z;
    Point() {}
    Point(int x, int y, int z): x(x), y(y), z(z) {}
    bool operator<(const Point 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;
    }
};

vector<Point>a;
set<Point>a4, ano4;
ll maxDis;

ll getDis(Point a, Point 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);
}

void init() {
    maxDis = -1;
    a4.clear(), ano4.clear();
}

bool sol() {
    init();
    for (int i = 0; i < 8; ++i)
        for (int j = 0; j < i; ++j)
            if (!(a[i] < a[j]) and !(a[j] < a[i]))return false;
    vector<ll>diss;
    for (int i = 0; i < 8; ++i)
        for (int j = 0; j < i; ++j)
            diss.push_back(getDis(a[i], a[j]));
    sort(diss.begin(), diss.end());
    for (int i = 0; i < 12; ++i)
        for (int j = 0; j < j; ++j)
            if (diss[i] != diss[j])return false;
    for (int i = 0; i < 12; ++i)
        for (int j = 0; j < j; ++j)
            if (diss[12 + i] != diss[12 + j])return false;
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < i; ++j)
            if (diss[24 + i] != diss[24 + j])return false;
    if (diss[0] + diss[12] != diss[24]) return 0;
    return true;
}

void solve() {
    a.resize(8);
    for (int i = 0; i < 8; ++i) {
        cin >> a[i].x >> a[i].y >> a[i].z;
    }
    cout << (sol() ? "YES\\n" : "NO\\n");
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int _;
    for (cin >> _; _--;) solve();
    return 0;
}

F. Fair Distribution

\\(n\\) 只能减少(并且 \\(n\\) 不能为 \\(0\\)),\\(m\\) 只能增加,求出最终达到状态使 \\(n*k=m\\) 时,\\(n\\) 减少的值与 \\(m\\) 增加的值之和最小。


数论题(分治处理),类似某场ARC的题

  • \\(n >= m\\) 时,不难发现输出 \\(n-m\\) 即可

  • \\(n < m\\) 时,我们可以枚举n来求出最终答案,但是枚举并不是一个一个加,因为中间的值在跳跃,所以我们每次确定一个 \\(l\\)\\(r = min(n,(m - 1)/((m-1)/l))\\) ,而下个 \\(l = r + 1\\)

    此时 \\(k = ⌊\\frac{m-1}i*i⌋\\)

using ll = long long;
void solve() {
    ll n, m; cin >> n >> m;
    if (n > m)cout << n - m << "\\n";
    else {
        ll cnt = 0x3f3f3f3f;
        for (ll l = 1, r; l <= n; l = r + 1) {
            r = min(n, (m - 1) / ((m - 1) / l));
            cnt = min(cnt, (m - 1) / l * l);
        }
        cout << cnt + n - m << \'\\n\';
    }
}

G. Wall Game

题意待补


// 待补#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\\t"<< #b << ": " << b << "\\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\\t"<< #b << ": " << b <<"\\t"<< #c << ": " << c << "\\n";
using namespace std;
int debug = 0;
ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}
inline int read() {
    int s = 0, f = 1;
    char ch = getchar();
    while (ch < \'0\' || ch > \'9\') {
        if (ch == \'-\') f = -1;
        ch = getchar();
    }
    while (ch >= \'0\' && ch <= \'9\') {
        s = s * 10 + ch - \'0\';
        ch = getchar();
    }
    return s * f;
}
const int N = 5e5 + 7;
int fa[N];
int w[N];
map<pii, int> mp;
int dir[6][2] = {0, 1, 1, 0, 1, -1, 0, -1, -1, 0, -1, 1};
int find(int x) {
    return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void solve() {
    int n = read();
    int tot = 0;
    while (n--) {
        int op = read(), x = read(), y = read();
        if (op == 1) {
            mp[m_p(x, y)] = ++tot;
            fa[tot] = tot;
            w[tot] = 6;
            int sum = 0;
            int minus = 0;
            int cnt = 0;
            set<int> ss;
            vector<pii> vv;
            rp(k, 0, 5) {
                int nx = x + dir[k][0];
                int ny = y + dir[k][1];
                if (mp.find(m_p(nx, ny)) == mp.end()) continue;
                int id = find(mp[m_p(nx, ny)]);
                vv.push_back(m_p(k, id));
                if (ss.find(id) != ss.end()) cnt++;
                else {
                    cnt++;
                    sum += w[id];
                    ss.insert(id);
                }
            }
            int len = vv.size();
            rp(k, 0, len - 1) {
                rp(j, 0, len - 1) {
                    if (vv[k].first == 0 && vv[j].first == 1 && vv[k].second != vv[j].second) minus++;
                    if (vv[k].first == 1 && vv[j].first == 2 && vv[k].second != vv[j].second) minus++;
                    if (vv[k].first == 2 && vv[j].first == 3 && vv[k].second != vv[j].second) minus++;
                    if (vv[k].first == 3 && vv[j].first == 4 && vv[k].second != vv[j].second) minus++;
                    if (vv[k].first == 4 && vv[j].first == 5 && vv[k].second != vv[j].second) minus++;
                    if (vv[k].first == 5 && vv[j].first == 0 && vv[k].second != vv[j].second) minus++;
                }
            }
            for (auto val : ss) {
                // cout<<val<<" ";
                fa[val] = tot;
            }
            // cout<<endl;
            w[tot] = sum + w[tot] - 2 * cnt - 2 * minus;
            // cout<<w[tot]<<endl;
            // outval3(sum,cnt,minus);
        } else {
            cout << w[find(mp[m_p(x, y)])] << endl;
        }
    }
    // for(auto val:mp){
    // pii t=val.first;
    // outval3(t.first,t.second,find(mp[t]));
    // }
}
int main() {
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();
    solve();
    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

J. Grammy and Jewelry

题意待补


算是比较套路的题。

根据贪心的原则,我们每次取一个宝珠后应该立马返回到原点。

而我们到这个宝珠的位置走的路和返回时走的路应该是最短路。

转换一下就是我们要取一个价值为 \\(a[i]\\) 的宝珠,需要消耗容量为\\(2∗dis[i]\\) 的时间(\\(dis[i]\\) 表示从 \\(1\\)\\(i\\) 的最短路)。

这样就转换成了经典的完全背包问题。

关于背包问题不懂的可以看经典的背包九讲。

const int N = 3010, inf = 0x3f3f3f3f;
vector<int>e[N];
struct node {
    int u, w;
    node() {}
    node(int u, int w): u(u), w(w) {}
    friend bool operator <(node a, node b) {
        return a.w > b.w;
    }
};

int a[N], dis[N], vis[N], dp[N];
int n, m, t;
void Dijlstra() {
    priority_queue<node> q;
    for (int i = 1; i <= n; ++i)dis[i] = inf;
    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;
        // cout << u << " " << w << endl;
        for (auto v : e[u]) {
            // cout << v << " " << dis[v] << endl;
            if (!vis[v] && dis[v] > w + 1) {
                dis[v] = w + 1;
                q.push(node{v, dis[v]});
            }
        }
    }
}
void solve() {
    cin >> n >> m >> t;
    for (int i = 2; i <= n; ++i)cin >> a[i];
    for (int i = 1; i <= m; ++i) {
        int u, v; cin >> u >> v;
        if (u == v)continue;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    Dijlstra();
    for (int i = 1; i <= n; ++i)
        for (int j = dis[i] * 2; j <= t; ++j)
            dp[j] = max(dp[j], dp[j - dis[i] * 2] + a[i]);
    for (int i = 1; i <= t; ++i)cout << dp[i] << (i == t ? "\\n" : " ");
}

L. String Freshman

读了半天题,结果题意有问题。。。

给的字符串应该是匹配串。


因此我们判断一下是否存在前缀子串的最长公共前后缀长度不为 \\(0\\)(即 next 数组不为 \\(0\\) )。

更简单的做法就是判断是否有字符和第一个字符相等即可。

void solve() {
    int n; string s;
    cin >> n >> s;
    for (int i = 1; i <= n - 1; ++i)
        if (s[i] == s[0]) {
            cout << "Wrong Answer\\n";
            return ;
        }
    cout << "Correct\\n";
}

M. Game Theory

输出 0.0000 即可。

首先我们知道每个学生是不知道 \\(Grammy\\) 的选择,而又因为学生每次都是最优的选择,因此我们可以先算出一个学生在 \\([1 ,20]\\) 选择一个数后赢的分数的期望,每次都选择这\\(20\\) 个数中期望最大的即可。
我们写出计算期望的代码可以发现,每个数赢的分数的期望都是 \\(0\\)

而学生和 \\(Grammy\\) 的分数是互补的,只有一个输了,另一个赢了的情况

所以 \\(Grammy\\) 胜利的期望也是 \\(0\\)

void solve() {
    int n; cin >> n;
    cout << fixed << setprecision(4) << 0.0;
}

以上是关于The 18th Zhejiang Provincial Collegiate Programming Contest 补题记录(ACFGJLM)的主要内容,如果未能解决你的问题,请参考以下文章

ZJCPC2021 第18届 浙江省赛The 18th Zhejiang Provincial Collegiate Programming Contest(ACFGJLM 7题)

The 17th Zhejiang Provincial Contest B. Bin Packing Problem(线段树+map)

The 15th Zhejiang Provincial Collegiate Programming Contest(部分题解)

The 19th Zhejiang Provincial Collegiate Programming Contest F - Easy Fix(主席树)

The 19th Zhejiang Provincial Collegiate Programming Contest F - Easy Fix(主席树)

The 19th Zhejiang Provincial Collegiate Programming Contest F - Easy Fix(主席树)