CF1366 EDU89 菜鸡的ABC题解

Educational Codeforces Round 89 (Rated for Div. 2)

A.Shovels and Swords

题意:

已知有a个木棍和b个钻石,做一个钻石铲要2个木棍和1个钻石,做一把钻石剑需要1个木棍和2个钻石,问最多总共能做多少工具。

思路

刚读完题满脑子都是:这也太MC了吧 这可咋搞,然后就开始瞎推公式了QUQ。这个就是写出来吐槽一下自己的,可以跳过QUQ。

首先设钻石铲x把,钻石剑b把,依题意易得
a > = 2 ∗ x + y b > = x + 2 ∗ y a>=2*x+y\\b>=x+2*y a>=2x+yb>=x+2y
公式两边相加变成
( a + b ) / 3 > = x + y (a+b)/3>=x+y (a+b)/3>=x+y
得到x+y的最大值。也不懂昨晚在想什么,写到这里就脑子一抽地交上去莽(WA)了一发Orz这个公式,实际上a,b的数量可能无法达到这个最大值,所以再对不满足的情况处理一下就出了。

Code

#include <bits/stdc++.h>
#define re read()
#define ll long long
#define rep(a, b, c) for(int a = b; a <= c; a++)
#define per(a, b, c) for(int a = b; a >= c; a--)
using namespace std;
int read()
{
	int num = 0; bool f = 0; char ch = getchar();
	while(ch < '0' || ch > '9') {f = (ch == '-'); ch = getchar();}
	while(ch >= '0' && ch <= '9') {num = (num << 1) + (num << 3) + ch - '0'; ch = getchar();}
	return f? -num : num;
}
int main()
{
	per(T, re, 1)
	{
		int a = re, b = re;
		if(!a || !b) {puts("0"); continue;}
		int ans = (a + b) / 3;
		if(a <= ans) ans = min(a, b / 2);
		if(b <= ans) ans = min(ans, min(b, a / 2));
		printf("%d\n", ans);
	}
	return 0;
}

B.Shuffle

题意

给定n个数,第x个数为1,其余全为0。共给出m个区间,每次可将区间内任意两数位置交换,求有多少个位置在m次操作后可以为1。

思路

(废话一堆,可以直接看下一段)第一眼看完以为是输出任意一位最后可以是1的,差点就莽了,然后又去看了一波,看完人傻了,以为今晚就要跪在这里了QWQQQ然后对样例手做了一下,第一反应是做区间覆盖,感觉不太会写就又仔细想了一下。

注意,题意是每次总共只会有一个1,最后的答案是所有的可能情况之和。
题目后面补充了可以选择两个相同的数字进行交换(就是相当于可以不操作)所以,每次操作时,只要这个区间内有1存在,那么这个区间内每一个数字都可以在m次操作后为1。因此易知可以得到1的位置是一段连续区间(假设所给区间A与之前的连续区间交集为空,则区间A均不出现1)

所以我们用 l l l r r r记录连续区间的左右范围(显而易见 a n s = r − l + 1 ans=r-l+1 ans=rl+1),对于每次所给的区间,若其与 [ l , r ] [l,r] [lr]没有交集,则这个区间均不能有1。若有交,则可以用其对原连续区间进行更新。

Code

#include <bits/stdc++.h>
#define re read()
#define ll long long
#define rep(a, b, c) for(int a = b; a <= c; a++)
#define per(a, b, c) for(int a = b; a >= c; a--)
using namespace std;
int read()
{
	int num = 0; bool f = 0; char ch = getchar();
	while(ch < '0' || ch > '9') {f = (ch == '-'); ch = getchar();}
	while(ch >= '0' && ch <= '9') {num = (num << 1) + (num << 3) + ch - '0'; ch = getchar();}
	return f? -num : num;
}
int n, t, m, l, r;
int main()
{
	per(T, re, 1)
	{
		n = re, t = re, m = re;
		l = r = t;
		rep(i, 1, m)
		{
			int a = re, b = re;
			if(a > r || b < l) continue;
			l = min(l, min(t, a)), r = max(r, max(t, b));
		}
		printf("%d\n", r - l + 1);
	}
	return 0;
}

C.Palindromic Paths

题意

给定一个n*m的矩阵,矩阵中只有0/1,每次只能向左或右移动,求需要多少次更改,才可以使(1,1)->(n,m)的每一条路径均为回文。

思路

显而易见符合答案的矩阵,在到(1,1)和(n,m)的距离相等的点(距离相同的就是回文数的每一位),所对应的格子的值相等。所以题目就转换为把到(1,1)和(n,m)距离相等的所有点视为一组,并将这组点全部转换为0/1所需的最小次数,求和一下就是所要的答案。

因为只会笨笨的直观求和,所以画个图示意一下QUQ
这题的距离其实就是曼哈顿距离。如下图所示,每一条线上的每一个点到(1,1)的距离都相等(即 i + j i+j i+j相等)。利用回文串的思路,只需要把点按到(1,1)的距离相等的点划分为同一组进行统计即可。统计的部分写个三四条线就能找到规律了。

1355C示意图

注意:因为回文中间的一位并不影响回文的性质,所以最后求和的时候不需要对这组进行统计QUQ

我太菜了,这题主要的时间都花在推回文位置和求和的循环上QUQ

Code

#include <bits/stdc++.h>
#define re read()
#define ll long long
#define rep(a, b, c) for(int a = b; a <= c; a++)
#define per(a, b, c) for(int a = b; a >= c; a--)
using namespace std;
int read()
{
	int num = 0; bool f = 0; char ch = getchar();
	while(ch < '0' || ch > '9') {f = (ch == '-'); ch = getchar();}
	while(ch >= '0' && ch <= '9') {num = (num << 1) + (num << 3) + ch - '0'; ch = getchar();}
	return f? -num : num;
}
int n, m, ans;
int a[66], b[66];
int main()
{
	per(T, re, 1)
	{
		n = re, m = re; ans = 0;
		rep(i, 0, n + m) a[i] = b[i] = 0;
		rep(i, 1, n) 	
		{
			rep(j, 1, m)
			{
				int x = re;
				a[i + j] += x, b[i + j] += (!x);
			}
		}
		rep(i, 2, (n + m + 1) / 2)
			ans += min(a[i] + a[n + m + 2 - i], b[i] + b[n + m + 2 - i]);
		printf("%d\n", ans);
	}
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值