2020 年 “联想杯”全国高校程序设计在线邀请赛暨第三届上海理工大学程序设计竞赛 ABCDGHL

# =罚时ABCDEFGHIJKLM
70

NchuDreams

6622+
15
+
7
+2
25
+3
173
 -1+3+2
90
   +2
130
 

A、Archmage

注意法师会先召唤,再恢复法力值,所以最后一天的法力值是用不上的,然后和 m 取个 min 即可

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;
ll a[MAXN];
int main() 
{
    int T;
    sc("%d", &T);
    while (T--)
    {
        ll n, m, x, y;
        sc("%lld%lld%lld%lld", &n, &m, &x, &y);
        ll sum = min((n + y * (m - 1)) / x, m);
        pr("%lld\n", sum);
    }
}

B、Bamboo Leaf Rhapsody

看案例猜题意,直接输入最短距离

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;
int main()
{
    int n;
    sc("%d", &n);
    ll ans = 1e18;
    ll a, b, c;
    for (int i = 1; i <= n; i++)
    {
        sc("%lld%lld%lld", &a, &b, &c);
        ans = min(ans, a * a + b * b + c * c);
    }
    double res = sqrt(1.0*ans);
    pr("%.3lf\n", res);
}

C、Cheat Sheet

直接判断奇偶是否相同即可

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
map<string, bool>mp;
vector<string>v;
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> n >> m;
    while (m--)
    {
        string s;
        cin >> s;
        if (mp.count(s))
            continue;
        mp[s] = true;
        v.push_back(s);
    }
    sort(v.begin(), v.end(), [](string q, string w) {
        return q.size() < w.size();
        });
    int ans = -1, len = v.size();
    for (int i = 0; i < len; i++)
    {
        ans += v[i].size() + 1;
        if (ans > n)
        {
            cout << i;
            return 0;
        }
    }
    cout << len;
}

D、Disaster Recovery

考虑克鲁斯卡尔,将边按照边权从小到大排序,并且由 fib_n=fib_{n-1}+fib_{n-2} 可知,如果两条边最大的点越大,边权一定大,如果相同的话,比较小的点即可。

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
vector<int>v[MAXN];
int du[MAXN];
ll fib[MAXN];
struct node
{
    int x;
    int y;
}e[200005];
int que[100005];
void init()
{
    for (int i = 1; i < 100005; i++)
        que[i] = i;
}
int getf(int k)
{
    return que[k] == k ? k : que[k] = getf(que[k]);
}
int main()
{
    init();
    int n, m;
    sc("%d%d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        sc("%d%d", &e[i].x, &e[i].y);
        if (e[i].x < e[i].y)
            swap(e[i].x, e[i].y);
    }
    sort(e, e + m, [](node q, node w) {
        if (q.x != w.x)
            return q.x < w.x;
        return q.y < w.y;
        });
    for (int i = 0; i < m; i++)
    {
        int f1 = getf(e[i].x), f2 = getf(e[i].y);
        if (f1 != f2)
        {
            que[f1] = f2;
            du[e[i].x]++;
            du[e[i].y]++;
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans = max(ans, du[i]);
    pr("%d", ans);
}

G、Gentle Jena

每次给你一个数字,加在序列后面,并且求出当前序列的任意区间最小值之和,强制在线(n = 1e7)

显然需要一个线性时间,所以我们考虑每个数字能够贡献多少次即可,所以我们考虑维护一个单调增的序列,这样可以保证每次加入一个点,相对之前的答案的产生贡献的点都在这个单调增序列中,但是产生次数不知道,仔细思考可以发现,其实这个数字产生的次数就是这个数字在单调增序列左边的数字 和 这个数字之间的数字个数,所以每次维护一个 base 用来记录每次扩序列的增量即可。由于每个点只会被加入一次单调增序列,也只会被删除一次,所以整体复杂度是线性的。

注意取模一个是 p,一个是 998244353

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e7 + 5;
ll b[MAXN], a[MAXN];
stack<int>st;
int main()
{
	int n; ll mod, x, y, z;
	sc("%d%lld%lld%lld%lld%lld", &n, &mod, &x, &y, &z, &b[1]);
	ll ans = b[1];
	a[1] = b[1];
	st.push(0);
	st.push(1);
	ll base = a[1];
	for (int i = 2; i <= n; i++)
	{
		b[i] = (x * a[i - 1] + y * b[i - 1] + z) % mod;
		while (!st.empty() && b[st.top()] > b[i])
		{
			int tp = st.top();
			st.pop();
			base -= b[tp] * (tp - st.top());
		}
		base += b[i] * (i - st.top());
		st.push(i);
		a[i] = a[i - 1] + base;
		a[i] %= 998244353;
		ans = ans ^ a[i];
	}
	pr("%lld\n", ans);
}

H、Hay Mower

记录每行每列被割的最晚的时间,然后判断每个格子最晚什么时候被割即可

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 505;
ll s[MAXN][MAXN];
ll hang[MAXN], lie[MAXN];
const ll mod = 998244353;
int main()
{
	int n, m, k;
	sc("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			sc("%lld", &s[i][j]);
			s[i][j] %= mod;
		}
	ll ans = 0;
	for (int i = 1; i <= k; i++)
	{
		char op[2]; ll x, y;
		sc("%s%lld%lld", op, &x, &y);
		if (op[0] == 'r')
			hang[x] = y;
		else
			lie[x] = y;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			ans = (ans + s[i][j] * (max(hang[i], lie[j]) % mod)) % mod;
	pr("%lld\n", ans);
}

L、Lottery Tickets

枚举最后两位数字,按照最小的顺序来枚举最后两位,然后将其他数字从大到小顺序输出。

然后特判只有一个数字的情况和全0的情况。

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int a[11];
int main()
{
	int T;
	sc("%d", &T);
	while (T--)
	{
		int n = 10, cnt = 0;
		for (int i = 0; i < 10; i++)
		{
			sc("%d", &a[i]);
			cnt += a[i];
		}
		if (cnt == 1)
		{
			if (a[0] == 1)
				pr("0\n");
			else if (a[4] == 1)
				pr("4\n");
			else if (a[8] == 1)
				pr("8\n");
			else
				pr("-1\n");
			continue;
		}
		if (cnt == a[0])
		{
			pr("0\n");
			continue;
		}
		int q = -1, w = -1;
		if (a[0] >= 2)
		{
			q = 0, w = 0;
			a[0] -= 2;
		}
		else if (a[0] >= 1 && a[2] >= 1)
		{
			q = 2, w = 0;
			a[0]--;
			a[2]--;
		}
		else if (a[1] >= 1 && a[2] >= 1)
		{
			q = 1, w = 2;
			a[1]--;
			a[2]--;
		}
		else if (a[3] >= 1 && a[2] >= 1)
		{
			q = 3, w = 2;
			a[3]--;
			a[2]--;
		}
		else if (a[4] >= 1 && a[0] >= 1)
		{
			q = 4, w = 0;
			a[4]--;
			a[0]--;
		}
		else if (a[4] >= 1 && a[2] >= 1)
		{
			q = 2, w = 4;
			a[4]--;
			a[2]--;
		}
		else if (a[4] >= 2)
		{
			q = 4, w = 4;
			a[4] -= 2;
		}
		else if (a[5] >= 1 && a[2] >= 1)
		{
			q = 5, w = 2;
			a[5]--;
			a[2]--;
		}
		else if (a[6] >= 1 && a[0] >= 1)
		{
			q = 6, w = 0;
			a[6]--;
			a[0]--;
		}
		else if (a[6] >= 1 && a[1] >= 1)
		{
			q = 1, w = 6;
			a[6]--;
			a[1]--;
		}
		else if (a[6] >= 1 && a[3] >= 1)
		{
			q = 3, w = 6;
			a[6]--;
			a[3]--;
		}
		else if (a[6] >= 1 && a[4] >= 1)
		{
			q = 6, w = 4;
			a[6]--;
			a[4]--;
		}
		else if (a[6] >= 1 && a[5] >= 1)
		{
			q = 5, w = 6;
			a[6]--;
			a[5]--;
		}
		else if (a[7] >= 1 && a[2] >= 1)
		{
			q = 7, w = 2;
			a[7]--;
			a[2]--;
		}
		else if (a[7] >= 1 && a[6] >= 1)
		{
			q = 7, w = 6;
			a[7]--;
			a[6]--;
		}
		else if (a[8] >= 1 && a[0] >= 1)
		{
			q = 8, w = 0;
			a[8]--;
			a[0]--;
		}
		else if (a[8] >= 1 && a[2] >= 1)
		{
			q = 2, w = 8;
			a[8]--;
			a[2]--;
		}
		else if (a[8] >= 1 && a[4] >= 1)
		{
			q = 8, w = 4;
			a[8]--;
			a[4]--;
		}
		else if (a[8] >= 1 && a[6] >= 1)
		{
			q = 6, w = 8;
			a[8]--;
			a[6]--;
		}
		else if (a[8] >= 2)
		{
			q = 8, w = 8;
			a[8]--;
			a[8]--;
		}
		else if (a[9] >= 1 && a[2] >= 1)
		{
			q = 9, w = 2;
			a[9]--;
			a[2]--;
		}
		else if (a[9] >= 1 && a[6] >= 1)
		{
			q = 9, w = 6;
			a[9]--;
			a[6]--;
		}
		else
		{
			if (a[0] >= 1)
				pr("0\n");
			else if (a[4] >= 1)
				pr("4\n");
			else if (a[8] >= 1)
				pr("8\n");
			else
				pr("-1\n");
			continue;
		}
		for (int i = 9; i >= 0; i--)
		{
			while (a[i])
			{
				pr("%d", i);
				a[i]--;
			}
		}
		pr("%d%d\n", q, w);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值