湖南工学院2021级ACM正式队员第四次周测题解

A题薯条派对

来源:Codeforces Round #582 (Div. 3), problem: (A) Chips Moving

考察:思维

因为奇数坐标要想移动到偶数坐标上需要花费 1 原石(无论怎样都需要花费一原石),因为 2 个 2步移动都是免费的,最后总是要剩下一个。偶数坐标移动到奇数坐标上也是如此。可以先统计奇数个数,最后比较奇数个和偶数个大小即可。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll mod = 998244353;
int main() {
	int n;
	cin >> n;
	int ans1 = 0, ans2 = 0;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		if (x % 2 == 0) {
			ans1++;
		}else{
			ans2++;
		}
	}
	cout << min(ans1, ans2);
	return 0;
}

B题泡面派对

来源:Codeforces Round #777 (Div. 2), problem: (A) Madoka and Math Dad

考察:思维,规律

题目要求构造各位不包含0,各位相加等于n且相邻两位不同的最大的数,想要构造最大的数最好就是位数多,位数越多构造出来的数越大,根据要求相邻两位不能相同,所以取两个最小的正整数1和2来构造答案。
可以发现,构造出来的答案一定是1和2交替出现,既然要交替出现,那么1和2的数量最多相差一个。
∵ 1 + 2 = 3
∴ 如果 n 是 3 的倍数,那么构造出来的数所包含的1 和 2 的数量是相等的
如果 n % 3 = 2,n - 2可以构造等量的1和2 ,剩下一个2只能构造为2而不是两个1,如果构造两个1,1的数量就会比2多两个,必定会出现连续的两个1
如果 n % 3 = 1,则只能多构造一个1

然后选取数量多的那一个数作为开头,如果数量相等则用2开头。

#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 998244353;
using namespace std;
int main() {
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		if (n == 1 || n == 2) {
			cout << n << endl;
		}
		else {
			if (n % 3 == 1) {
				cout << 1;
				for (int i = 1; i <= n / 3; i++) {
					cout << "21";
				}
			}
			else if (n % 3 == 2) {
				cout << 2;
				for (int i = 1; i <= n / 3; i++) {
					cout << "12";
				}
			}
			else {
				for (int i = 1; i <= n / 3; i++) {
					cout << "21";
				}
			}
			cout << endl;
		}
	}
	return 0;
}

C题奶茶派对

来源:Codeforces Round #791 (Div. 2), problem: (A) AvtoBus

考察:思维,数学逻辑

设中杯的数量为 x,三大杯的数量为 y。那么等式 4x+6y=n一定为真。如果 n 是奇数,则没有答案,因为等式的左边部分总是偶数。现在我们可以将等式的每一部分除以二:2x+3y=eq?%5Cfrac%7Bn%7D%7B2%7D

让我们最大化奶茶的数量。然后我们应该使 x 尽可能大。因此,如果 eq?%5Cfrac%7Bn%7D%7B2%7D 是偶数,我们将得到 2+…+2+2=eq?%5Cfrac%7Bn%7D%7B2%7D,否则,我们将得到 2+…+2+3=eq?%5Cfrac%7Bn%7D%7B2%7D。在这两种情况下,总线的数量都是⌊eq?%5Cfrac%7Bn%7D%7B2%7D⌋。

现在让我们最小化奶茶的数量。因此,我们应该使 y 尽可能大。如果 eq?%5Cfrac%7Bn%7D%7B2%7D 可以被 3 整除,我们将得到 3+…+3+3+3=eq?%5Cfrac%7Bn%7D%7B2%7D,如果 n%3=2 则得到 3+…+3+3+2=eq?%5Cfrac%7Bn%7D%7B2%7D,并且 3+…+3+2+2 =eq?%5Cfrac%7Bn%7D%7B2%7D 如果 n%3=1。在所有情况下,奶茶的数量都是⌈eq?%5Cfrac%7Bn%7D%7B3%7D⌉。

也不要忘记 n<4 的情况——每杯奶茶最低4元,所以在这种情况下没有答案。

#include <bits/stdc++.h>
using namespace std;
int main(){
  int t;
  cin >> t;
  for (int i = 0; i < t; i++){
    long long n;
    cin >> n;
    if (n % 2 == 1 || n == 2){
      cout << -1 << endl;
    } else {
      cout << (n + 4) / 6 << ' ' << n / 4 << endl;
    }
  }
}

D题辣片派对

原题链接:木棍加工 - 洛谷

考察:裸LIS

E题糖果派对

来源:Codeforces Global Round 17, problem: (C) Keshi Is Throwing a Party

考察:稍加思考的二分答案

本题我们可以发现每个人的糖果数目是固定不变的,也就是说可以通过他当前的编号来推算前面和后面有多少人来确定是否满足ai和bi。因此我们可以二分答案人数,假设人数为n,对于每个人,若前面已经选了x人,那么必须bi大于等于x,因为包括本身来说,后面剩下的那些人,我们最多可以选择n-x-1人,因此只要ai大于n-x-1,那么当前这个人就可以选,并且x++。若当前n人选满了,那么左端点往右移,去尝试更大的答案,否则右端点往左移。因此就可以得出最大的人数。时间复杂度为O(nlog(n))。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll mod = 998244353;
int a[202020], b[202020];
int n;
int isok(int x) {
	int y = 0;
	int z = x;
	for (int i = 1; i <= n; i++) {
		if (b[i] >= y && x && a[i] >= x - 1) {
			y++;
			x--;
		}
	}
	if (y == z) {
		return 1;
	}
	else {
		return 0;
	}
}
int main() {
	int t;
	cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> a[i] >> b[i];
		}
		int l = 1, r = n + 10;
		while (l <= r) {
			int mid = l + r >> 1;
			if (isok(mid)) {
				l = mid + 1;
			}
			else {
				r = mid - 1;
			}
		}
		cout << r << endl;
	}
	return 0;
}

 F题汉堡派对

来源:Codeforces Round #363 (Div. 2), problem: (D) Vacations

考察:基础线性dp

这个问题可以用动态规划来解决。让我们解决相反的问题,找出操作的最大次数。我们需要使用二维数组 dp,其中 dp[i][j] 等于操作的最大次数,如果当前是第 i 次操作并且 j 等于:

  • 0,则不操作。
  • 1、在第 i 次操作添加牛肉饼,
  • 2,在第 i 次操作添加番茄酱。

dp数组中 i 表示第 i 次操作,j 表示不操作还是加牛肉饼或者番茄酱。

然后对于第 i 次操作来说,它可以由前面的 i - 1 次操作得出:

  • dp[i][0] 必须用数组 dp 前一天的最大值更新;

  • 如果在第 i 天加牛肉饼(即 ai 等于 1 或 3),则我们将 dp[i][1] 更新为 dp[i - 1][0] + 1 和 dp[i - 1][2] + 1 的最大值;

  • 如果在第 i 天加番茄酱(即 ai 等于 2 或 3),则我们将 dp[i][2] 更新为 dp[i - 1][0] + 1 和 dp[i - 1][1] + 1 的最大值。

之后,我们需要从数组 dp 的所有值中选择最后一天的最大值并输出 n - max 即可。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll mod = 998244353;
int dp[200][10];
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		if (x == 1) {
			dp[i][1] = max(dp[i - 1][0], dp[i - 1][2]) + 1;
		}
		if (x == 2) {
			dp[i][2] = max(dp[i - 1][0], dp[i - 1][1]) + 1;
		}
		if (x == 3) {
			dp[i][1] = max(dp[i - 1][0], dp[i - 1][2]) + 1;
			dp[i][2] = max(dp[i - 1][0], dp[i - 1][1]) + 1;
		}
		dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1], dp[i - 1][2]));
	}
	int maxn = 0;
	for (int i = 0; i <= 2; i++) {
		maxn = max(maxn, dp[n][i]);
	}
	cout << n - maxn;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值