Codeforces Round #809 Editorial(A,B,C)

A. Another String Minimization Problem

题意:你有一个长度为n的序列a1,a2,...,an,由1到m之间的整数组成,你也有一个字符串s,由m个字符B组成。你要进行以下n个操作。

在第i次(1≤i≤n)操作中,你用A替换s的第ai个或(m+1-ai)个字符,你可以通过操作多次替换任何位置的字符。
找出经过这些操作后,你能得到的最小的乐谱学上的字符串。

当且仅当在x和y不同的第一个位置上,字符串x有一个字母在字母表中出现的时间比y中相应的字母早,则该字符串x在词典上小于相同长度的字符串y。

思路:按照要求从头开始往后处理,优先处理位置靠前的,如果位置靠前的已经是A了,那么就把位置靠后的变成A。

代码:

#include <iostream>
 
using namespace std;
 
const int N = 60;
 
int t, n, m, a[N];
char c[N];
 
int main()
{
	cin >> t;
	while(t -- )
	{
		cin >> n >> m;
		for(int i = 1; i <= m; i ++ ) c[i] = 'B';
		for(int i = 1; i <= n; i ++ ) cin >> a[i];
		
		for(int i = 1; i <= n; i ++ )
		{
			int x1 = a[i], x2 = m + 1 - a[i];
			int x3 = min(x1, x2), x4 = max(x1, x2);
			if(c[x3] != 'A') c[x3] = 'A';
			else c[x4] = 'A';
		}
		for(int i = 1; i <= m; i ++ ) cout << c[i];
		cout << endl;
	}
	return 0;
}

B. Making Towers 

题意:你有一个由n个色块组成的序列。第i个图块的颜色是ci,是1到n之间的一个整数。你将以如下方式在一个无限的坐标网格上依次放置积木。
最初,你把块1放在(0,0)处。
对于2≤i≤n,如果第(i-1)个图块被放置在位置(x,y),那么第i个图块可以被放置在位置(x+1,y)、(x-1,y)、(x,y+1)之一(但不能放置在位置(x,y-1)),只要之前没有图块放置在这个位置。
一个塔是由s个图块组成的,这些图块被放置在(x,y),(x,y+1),...,(x,y+s-1)的位置上,对于某个位置(x,y)和整数s。颜色为r的塔是一个塔,其中所有的块都有r的颜色。
对于从1到n的每一种颜色r,独立解决以下问题。

找出根据规则放置积木所能形成的r色塔的最大尺寸。

思路:我们可以发现,两块相同颜色的木块如果要放在上下相邻,那么这两个塔必须中间间隔偶数的其他块或者中间没有其他数,只有这样才能刚好放在上下相邻的位置。那么可以发现,该问题就是找到颜色相同的序列,且相邻的两个数的下标奇偶性不同。我们不需要两重循环来枚举所有从ai开始的最大长度,因为我们考虑ai后面的aj和ak,j < k,此时ai后面可以接aj和ak,如果最优解是接ak,那么我们可以将最优解转化为接aj,因为aj和ak可以接在ai后面,那么此时aj和ak的下标的奇偶相同,那么ak后面最优解的序列此时也可以接在aj后面,所以我们不需要两重循环,而是贪心的去找aj,如果aj和ai奇偶不同,那么就选择aj,然后此时将j作为末尾继续去找。

代码如下: 

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int t, f[N][2], color[N], n;

int main()
{
	scanf("%d", &t);
	while(t -- )
	{
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++ ) scanf("%d", &color[i]);
		for(int i = 1; i <= n; i ++ ) f[i][0] = f[i][1] = 0;
		
		for(int i = 1; i <= n; i ++ )
		{
			f[color[i]][i & 1] = f[color[i]][(i & 1) ^ 1] + 1;
		//	printf("f[%d][%d] = f[%d][%d] + 1 = %d\n", color[i], i & 1, color[i], (i & 1) ^ 1, f[color[i]][i & 1]);
		}
		for(int i = 1; i <= n; i ++ )
		cout << max(f[i][1], f[i][0]) << ' ';			//不确定最后是奇结尾还是偶结尾,所以取max简化了程序 
		cout << endl;
	}
	return 0;
}

C. Qpwoeirut And The City

题意:Qpwoeirut已经开始学习建筑,并雄心勃勃地决定改造他的城市。

Qpwoeirut的城市可以被描述为一排n栋楼,其中第i栋(1≤i≤n)楼高为hi层。你可以假设这个问题中每层楼的高度都是相等的。因此,当且仅当建筑i的楼层数hi大于建筑j的楼层数hj时,建筑i才比建筑j高。

如果i号楼比i-1号楼和i+1号楼都高(而且都存在),那么i号楼就很酷。请注意,第1栋和第n栋建筑都不可能是凉爽的。

为了改造城市,Qpwoeirut需要使凉爽建筑的数量最大化。为了做到这一点,Qpwoeirut可以在任何建筑物的顶部建造额外的楼层,以使其更高。注意,他不能拆除已经存在的楼层。

由于建造新的楼层很昂贵,Qpwoeirut希望尽量减少他建造的楼层数量。找到Qpwoeirut需要建造的最少楼层数,以使凉爽的建筑物数量最大化。

Input:

6
3
2 1 2
5
1 2 1 4 3
6
3 1 4 5 5 2
8
4 2 1 3 5 3 6 1
6
1 10 1 1 10 1
8
1 10 11 1 10 11 10 1

Output:

2
0
3
3
0
4

思路:奇数的情况是确定的,就是从2开始间隔一位就get一下之间的差值。偶数情况是不确定的,比如

4 23 5 3 6 1
2 1 3 5 3 6 1
2 1 3 5 3 6 1
4 2 1 3 5 3 6 1

容易发现,对于偶数,它有一位的自由空间,这导致了最后一个位置可以往后移一位,得到序列2

在序列2的基础上把倒数第二个数往后移1位,得到序列3…………,直到把第一位往后移动1位。所以一共要处理O(n)次,序列2是在序列1的基础上,最后一位不同,所以减去最后一位加上的值,然后再补上最后一位移动的值。得到序列3需要的块数,依次类推,可以在O(n)的时间内将所有情况找出来,然后用ans取最大保存即可。

代码如下:

#include "bits/stdc++.h"

using namespace std;

typedef long long ll;
const int N = 100100;

int t, n;
ll a[N];

ll get(int i) 
{
  return max(0ll, max(a[i - 1], a[i + 1]) - a[i] + 1);
}

int main() 
{
	scanf("%d", &t);
	while (t--) 
	{
		scanf("%d", &n);
    	for (int i = 1; i <= n; i++) cin >> a[i];
		if (n & 1) 
		{
			
    		ll ans = 0;
    		for (int i = 2; i < n; i += 2)
   		 	ans += get(i);
		
   		 	cout << ans << endl;
    		continue;
   		}

 	    ll tot = 0;
 	    for (int i = 2; i < n; i += 2)
 	    tot += get(i);
	
	    ll ans = tot;
  	    for (int i = n - 1; i > 1; i -= 2) 
	    {
    		tot -= get(i - 1);
    		tot += get(i);
    		ans = min(ans, tot);
        }

   		cout << ans << endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一万次悲伤_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值