The 18th Zhejiang Provincial Collegiate Programming Contest

A. League of Legends

求出 B B B A A A队员的 H P HP HP总和,比较大小输出答案

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n = 0, m = 0;
    for(int i = 1;i <= 5;i++)
    {
        int tt;
        cin >> tt;
        n += tt;
    }
    for(int i = 1;i <= 5;i++)
    {
        int tt;
        cin >> tt;
        m += tt;
    }
    if(n >= m)
    cout << "Blue" << '\n';
    else
    cout << "Red" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

M. Game Theory

每个学生都相对独立,由于选择每个数字的概率相同,且加分等于减分,所以最终期望为 0 0 0

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    cout << "0" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

C. Cube

计算出各个点之间的距离,和各个距离的数量,如果距离的平方之比为 1 : 2 : 3 1:2:3 1:2:3且个数之比为 12 : 12 : 4 12:12:4 12:12:4则可以组成一个正立方体

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n = 8;
    int x[10], y[10], z[10];
    map<int, int> m;
    for(int i = 1;i <= n;i++)
    cin >> x[i] >> y[i] >> z[i];
    for(int i = 1;i <= n;i++)
    {
        for(int j = i + 1;j <= n;j++)
        {
            int dis = (x[j] - x[i]) * (x[j] - x[i]) + (y[j] - y[i]) * (y[j] - y[i]) + (z[j] - z[i]) * (z[j] - z[i]);
            m[dis]++;
        }
    }
    int sum = 0;
    vector<int> a, b;
    for(auto i : m)
    {
        a.push_back(i.first);
        b.push_back(i.second);
    }
    if(a.size() != 3)
    cout << NO << '\n';
    else
    {
        sort(a.begin(), a.end());
        sort(b.begin(), b.end());
        if(a[0] * 2 == a[1] && a[0] * 3 == a[2] && b[0] * 3 == b[1] && b[0] * 3 == b[2])
        cout << YES << '\n';
        else
        cout << NO << '\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

J. Grammy and Jewelry

通过 b f s bfs bfs计算得每个点距离 1 1 1的最短距离,记作 w [ i ] w[i] w[i],每个点的珠宝价值记作 v [ i ] v[i] v[i],由于珠宝可以无限拿,所以最后可以转化为完全背包问题

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
int v[5005], vis[5005], w[5005], dp[5005];
vector<int> G[5005];
void bfs()
{
	queue<pii>que;
	que.push({1, 0});
	while (!que.empty()) {
		int u = que.front().first;
        int dis = que.front().second;
		que.pop();
		for (auto it : G[u]) 
        {
			if (!vis[it]) 
            {
				vis[it] = 1;
				w[it] = dis + 2;
				que.push({it, dis + 2});
			}
		}
	}
}
void solve()
{
    int n, m, k;
    cin >> n >> m >> k;
    for(int i = 2;i <= n;i++)
    {
        cin >> v[i];
        w[i] = INF;
    }
    for(int i = 1;i <= m;i++)
    {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vis[1] = 1;
    bfs();
    // for(int i = 2;i <= n;i++)
    // cout << w[i] << " " << v[i] << '\n';
    for(int i = 1;i <= n;i++)
    {
        for(int j = w[i]; j <= k;j++)
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
    }
    for(int i = 1;i <= k;i++)
    cout << dp[i] << " ";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

L. String Freshman

题目给出一个假的 K M P KMP KMP算法,当匹配失败时它并没有像 K M P KMP KMP算法那样跳到 n e x nex nex继续匹配,而是变成从头匹配,这样会导致计数错误

为了 h a c k hack hack这段代码,我们只需要查找字符串中是否有字符与第一个字符相同,若有,则 h a c k hack hack成功

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    for(int i = 1;i < n;i++)
    {
        if(s[i] == s[0])
        {
            cout << "Wrong Answer" << '\n';
            return;
        }
    }
    cout << "Correct" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

F. Fair Distribution

假设最后剩下 x x x个机器人,那最后剩下能量棒个数为 ⌈ m x ⌉ ∗ x \lceil \frac{m}{x} \rceil *x xmx

a n s = n − x + ⌈ m x ⌉ ∗ x − m ans = n - x + \lceil \frac{m}{x} \rceil *x - m ans=nx+xmxm
= n − x + ⌊ m + x − 1 x ⌋ ∗ x − m = n - x + \lfloor \frac{m + x - 1}{x} \rfloor * x - m =nx+xm+x1xm
= ( ⌊ m − 1 x ⌋ − 1 + 1 ) ∗ x + n − m = (\lfloor \frac{m - 1}{x} \rfloor - 1 + 1) * x + n - m =(⌊xm11+1)x+nm
= ⌊ m − 1 x ⌋ ∗ x + n − m = \lfloor \frac{m - 1}{x} \rfloor * x + n - m =xm1x+nm

由于 ⌊ m − 1 x ⌋ \lfloor \frac{m - 1}{x} \rfloor xm1的值可以分块维护,所以我们可以在时间复杂度 O ( n l o g m ) O(nlogm) O(nlogm)求得答案

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n, m;
    cin >> n >> m;
    if(m <= n)
    cout << n - m << '\n';
    else
    {
        int mn = INF;
        for(int l = 1, r;l <= n;l = r + 1)
        {
            r = (m - 1) / ((m - 1) / l);
            mn = min(mn, (m - 1) / l * l);
            //cout << l << " " << r << '\n';
        }
        cout << mn + n - m << '\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

G. Wall Game

首先,我们可以将坐标化成点存储在 m a p map map中,由图可知,每个蜂巢相邻着六个蜂巢,所以每次加入蜂巢后,我们可以遍历它周围的六个蜂巢,如果之前的蜂巢出现过,则通过并查集的方式把出现过的蜂巢块加到当前蜂巢下,同时记录当前蜂巢块内有多少个蜂巢和重复的蜂巢个数

查询时,如果当前蜂巢没出现过,则它的六条边都没被占用,则输出 6 6 6,如果当前蜂巢出现过,则通过并查集找到它的祖先,输出 6 ∗ 6* 6蜂巢个数 − 2 ∗ -2* 2重复蜂巢个数

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
int xx[6] = {0, 1, 1, 0, -1, -1};
int yy[6] = {1, 0, -1, -1, 0, 1};
int fa[N], num[N], cf[N];
int findfa(int x)
{
    if(fa[x]!=x)
        fa[x] = findfa(fa[x]);
    return fa[x];
}
void solve()
{
    int n;
    cin >> n;
    map<pii, int> m;
    int cnt = 0;
    for(int i = 1;i <= n;i++) fa[i] = i;
    for(int i = 1;i <= n;i++)
    {
        int op, x, y;
        cin >> op >> x >> y;
        if(op == 1)
        {
            num[++cnt] = 1;
            m[{x, y}] = cnt;
            for(int j = 0;j < 6;j++)
            {
                int t1 = x + xx[j];
                int t2 = y + yy[j];
                if(m[{t1, t2}])
                {
                    int tt = findfa(m[{t1, t2}]);
                    if(tt != cnt)
                    {
                        fa[tt] = cnt;
                        num[cnt] += num[tt];
                        cf[cnt] += cf[tt] + 2;
                    }
                    else
                    cf[cnt] += 2;
                }
            }
        }
        else
        {
            if(!m[{x, y}])
            cout << "6" << '\n';
            else
            {
                int p = findfa(m[{x, y}]);
                if(num[p] == 1)
                cout << "6" << '\n';
                else
                cout << num[p] * 6 - cf[p] << '\n';
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

I. Grammy and Ropes

由图可知:
1 1 1 2 2 2圆相交与点 1 1 1 4 4 4
1 1 1 3 3 3圆相交与点 2 2 2 5 5 5
2 2 2 3 3 3圆相交与点 3 3 3 6 6 6

s u m sum sum为两个圆中的冲突个数(例如 1 1 1 2 2 2圆,如果在点 1 1 1是圆 1 1 1在圆 2 2 2上但是在点 4 4 4是圆 2 2 2在圆 1 1 1上,我们认为这两个圆有冲突)

如果 s u m = 0 sum = 0 sum=0,不会出现圆与圆之间相互嵌套的情况,即至少剪掉一个圆后所有的圆都能拿走。为什么说至少呢,因为存在形如 1 > 2 , 2 > 3 , 3 > 1 1>2,2>3,3>1 1>2,2>3,3>1等情况,我们必须要剪掉其中一个圆才能使这个“死循环”解放出来,所以一个都不剪是不行的,这种情况输出 7 7 7。如果没有出现这种死循环,说明即使一个圆也不剪掉,也有一个圆在最上方,可以直接被拿走,这种情况输出 8 8 8

s u m > 0 sum > 0 sum>0时,先来看至少剪掉两个圆的情况,这种情况下最多只会剩下一个圆,所以无论如何也能成功拿走所有的圆, a n s ans ans的初始值就为 4 4 4,那如何和 s u m sum sum联系在一起呢,如果两个圆之间没有冲突,那我们可以剪掉另外一个圆使得剩下这两个没有冲突的圆可以被直接拿走,所以最后 a n s = 4 + s u m ans = 4 + sum ans=4+sum,输出 a n s ans ans即可

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
int a[10];
void solve()
{
    for(int i = 1;i <= 6;i++)
    {
        string s;
        cin >> s;
        if(s[0] == 't')
        a[i] = 1;
        else
        a[i] = 0;
    }
    int sum = 0;
    for(int i = 1;i <= 3;i++)
    {
        if(a[i] == a[i + 3])
        sum++;
    }
    if(sum == 3)
    {
        if(a[1] == 0 && a[2] == 0 || a[2] == 1 && a[3] == 1 || a[1] == 1 && a[3] == 0) // 有一个绳子在最上面
        cout << "8" << '\n';
        else
        cout << "7" << '\n';
    }
    else
    cout << 4 + sum << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}
  • 33
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值