[补题] 2021华中师范大学程序设计新生赛

比赛链接:“菜鸟杯”华中师范大学程序设计新生赛(同步赛)_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

I.宝藏欲しい

思路:

存储词典时,用map实现从古语言到现代语言的映射。

因为输出时,若无法实现翻译应输出“-1”,所以可以将已经完成翻译的古语言存入队列,若中途出现词典以外的古语言就做一个标志,若能成功翻译就逐一输出队首。

代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 110;

int n;
map<string,string> m;

signed main()
{
	cin >> n;
	while(n--)
	{
		string a, b;
		cin >> a >> b;
		m[b] = a;
	}
	string s;
	queue<string> q;
	bool flag = 0;
	while(cin >> s)
	{
		if(m.count(s)) q.push(m[s]);
		else flag = 1;
	}
	if(flag) puts("-1");
	else
	{
		while(q.size())
		{
			printf("%s ", q.front().c_str());
			q.pop();
		}
	}

	return 0;
}

F.加入光荣的进化吧!

思路:

暴力枚举在小范围打表可以发现规律,若设X<=Y<=Z,则当且仅当X:Y:Z == 1:2:3时,满足题意。

于是可以很容易地写出代码。

代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long

int t, x, y, z, ans;

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}

/* 打表 --> yyds */
// void yyds()
// {
// 	for(int i = 1; i <= 100; i++)
// 	{
// 		for(int j = 1; j <= 100; j++)
// 		{
// 			for(int k = 1; k <= 100; k++)
// 			{
// 				int d = gcd(gcd(i, j), k);
// 				if(i + j + k == i * j * k / d / d) 
// 					printf("%lld %lld %lld\n", i, j, k);
// 			}
// 		}
// 	}
// }

signed main()
{
	//yyds();	
	cin >> t;
	while(t--)
	{
		scanf("%lld %lld %lld", &x, &y, &z);
		ans = min(x, min(y/2, z/3));
		ans += min(x, min(z/2, y/3));
		ans += min(y, min(x/2, z/3));
		ans += min(y, min(z/2, x/3));
		ans += min(z, min(x/2, y/3));
		ans += min(z, min(y/2, x/3));
		printf("%lld\n", ans);
	}
	
	return 0;
}

E.Swap!Swap!Swap!Swap!Swap!

思路:

最小花费:

可以发现,一定可以在花费为0的前提下完成排序,因此最小花费即为0。

交换方法:

储存并维护一个映射,由排序完成的数组的下标i映射到其在当前数组的下标j,设映射的下标为t。

当 t - i >= n / 2 时,交换为:(a[i], a[t])

当 i , t <= n / 2 时,交换为:(a[i], a[n]), (a[j], a[n]), (a[i], a[n])

当 i , t > n / 2 时,交换为:(a[i], a[1]), (a[j], a[1]), (a[i], a[1])

当 i <= n / 2 and t > n / 2 时,交换为:(a[i], a[n]), (a[1], a[n]), (a[1], a[t]), (a[1], a[n]), (a[i], a[n])

当 i > n / 2 and t <= n / 2 时,交换为:(a[t], a[n]), (a[1], a[n]), (a[1], a[i]), (a[1], a[n]), (a[t], a[n])

代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
const int maxn = 5e5 + 10;

int n, a[maxn], b[maxn], cost, num;
map<int,int> mp, m;
vector<PII> ans;

signed main()
{
	cin >> n;
    for(int i = 1; i <= n; i++) 
    {
        scanf("%lld", &a[i]);
        mp[a[i]] = i;
    }
    
    int L = 1, R = n, mid = n >> 1;
    for(int i = 1; i <= n; i++)
    {
        int t = mp[i];
        if(i == t) continue;
        else if(t - i >= mid)
        {
            ans.push_back({i, t});
            num ++;
        }
        else if(i <= mid && t <= mid)
        {
            ans.push_back({i, R});
            ans.push_back({t, R});
            ans.push_back({i, R});
            num += 3;
        }
        else if(i > mid && t > mid)
        {
            ans.push_back({i, L});
            ans.push_back({t, L});
            ans.push_back({i, L});
            num += 3;
        }
        else if(i <= mid && t > mid)
        {
            ans.push_back({i, R});
            ans.push_back({L, R});
            ans.push_back({L, t});
            ans.push_back({L, R});
            ans.push_back({i, R}); 
            num += 5;
        }
        else if(i > mid && t <= mid)
        {
            ans.push_back({t, R});
            ans.push_back({L, R});
            ans.push_back({L, i});
            ans.push_back({L, R});
            ans.push_back({t, R});     
            num += 5;
        }
        mp[a[i]] = t, mp[i] = i;
        swap(a[i], a[t]);
    }
    printf("%lld\n%lld\n", cost, num);
    for(auto item : ans) printf("%lld %lld\n", item.first, item.second);

	return 0;
}

G.在CCNU寻求ACM是否搞错了什么?

思路:

可以发现答案为cal(x,y,z).

当n、m至少一个偶数时,有唯一可能,

① x = (n-2) * (m-2) >> 1, y = n + m - 4, z = 2.

当n、m都为奇数时,有两种可能,

① x = (n-2) * (m-2) >> 1, y = n + m - 2, z = 0.

② x = (n-2) * (m-2) >> 1, y = n + m - 6, z = 4.

代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long

int t, n, m, ans;

int cal(int x, int y, int z)
{
    int ret = 0;
    ret += 4 * (n*m + 1) * x - 4 * (1 + x) * x / 2;
    ret += 3 * (n*m + 1 - x) * y - 3 * (1 + y) * y / 2;
    ret += 2 * (n*m + 1 - x - y) * z - 2 * (1 + z) * z / 2;
    return ret;
}

signed main()
{
    cin >> t;
    while(t--)
    {
        scanf("%lld %lld", &n, &m);
        if((n%2)*(m%2) == 0) ans = cal((n-2)*(m-2)/2, n+m-4, 2);
        else 
        {
            ans = cal((n-2)*(m-2)/2, n+m-2, 0);
            ans = max(ans, cal((n-2)*(m-2)+1 >> 1, n+m-6, 4));
        }
        printf("%lld\n", ans);
    }
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值