Educational Codeforces Round 111 (Rated for Div. 2)

A. Find The Array

题意

要你构造一个长度为 n n n的数组,每个元素 a i a_i ai满足:

  1. a i = 1 a_i=1 ai=1
  2. a i − 1 a_i-1 ai1或者 a i − 2 a_i-2 ai2存在于数组中

现在要你构造一个元素和为 s s s的数组,问最短长度为多少

分析

贪心,让数组元素尽量大,但是因为 a i − 2 a_i-2 ai2必须在数组中,所以构造的是 1 , 3 , 5 , 7 , . . . 1,3,5,7,... 1,3,5,7,.... 最后一个数如果溢出可以将其减小至和恰好为 s s s,不影响性质。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
 
signed main()
{
	DDLC_ESCAPE_PLAN_FAILED;
	int t;
	cin >> t;
	while(t--)
	{
		int sum = 0;
		int n;
		cin >> n;
		for(int i = 1; ; i += 2){
			sum += i;
			if(sum >= n){
				cout << (i + 1) / 2 << endl;
				break;
			}
		}
	}
	return 0;
}

B. Maximum Cost Deletion

题意

给一个01串。每次操作可以选其中连续一段由相同字符构成的子串并将其删除。删除后剩下的部分保留顺序,拼接起来。每次删可以得到 a ⋅ l + b a·l+b al+b分( l l l为删的长度)。问删完后最大得分是多少

分析

考虑串中每个元素的平均贡献,即 a ⋅ l + b l = a + b l \frac{a·l+b}{l}=a+\frac{b}{l} lal+b=a+lb. 由此可知不管怎么删,每个元素都一定会贡献 a a a分。有变数的只有 b b b. 当 b ≥ 0 b\geq 0 b0,应让 l l l尽量小来最大化分数,所以 l = 1 l=1 l=1,答案是 总 长 度 ⋅ ( a + b ) 总长度·(a+b) (a+b);而若 b < 0 b<0 b<0,尽量让 l l l变大。所以尽可能地扩展长度,每次都把整个连续的串删掉。

这个时候,把字符串分成 x x x块,每块都是最长的连续的0或者1,这些块的邻居肯定是不同字符。每次删除之后,相邻字符会拼接起来。每次一个块一个块地删,最后总共删 x / 2 + 1 x/2+1 x/2+1次. 则答案为 a ⋅ l + ( x / 2 + 1 ) ⋅ b a·l+(x/2+1)·b al+(x/2+1)b

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
 
signed main()
{
	DDLC_ESCAPE_PLAN_FAILED;
	int t;
	cin >> t;
	while(t--)
	{
		int n, a, b;
		string s;
		cin >> n >> a >> b >> s;
		if(b > 0){
			cout << (int)s.size() * (a + b) << endl;
		}
		else{
			char now = '.';
			int cnt = 0;
			for(int i = 0; i < s.size(); ++i){
				if(s[i] != now){
					now = s[i];
					cnt++;
				}
			}
			cout << (cnt / 2LL + 1LL) * b + a * (int)s.size() << endl;
		}
	}
	return 0;
}

C. Manhattan Subarrays

题意

给数组 a a a,则规定其对应了平面上 n n n个点 ( a 1 , 1 ) , ( a 2 , 2 ) , . . . ( a i , i ) . . . (a_1,1),(a2,2),...(a_i,i)... (a1,1),(a2,2),...(ai,i)... 现在要求选出一个连续子数组,保证其长度小于3,或者从其中任选3个点 x , y , z x,y,z x,y,z,不可能有 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)。其中 d ( x , y ) d(x,y) d(x,y) ( a x , x ) (a_x,x) (ax,x) ( a y , y ) (a_y,y) (ay,y)曼哈顿距离,问可选出多少这样的子数组。

分析

由于各个点的 y y y坐标都不一样,可以画图。随意在坐标图上画3个 y y y坐标两两不同的点,改变它们 x x x坐标之间的关系。可以发现,当按 y y y坐标顺序看这三个点时,当且仅当它们的 x x x坐标单调不下降或者单调不上升时,有 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)

那么对于长度为4的子数组,我们需要判断4次,每次从其中任选3个判断一下。

但对于长度5的数组,我们发现,不管怎么画,都必定会出现 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)

因此,满足条件的数组最长长度为4。而长度为2,1的必定符合条件,故我们只需判断长度为3,4的即可。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn];
bool check(int x, int y, int z)
{
	if(a[x] <= a[y] && a[y] <= a[z]) return 0;
	if(a[x] >= a[y] && a[y] >= a[z]) return 0;
	return 1;
}
signed main()
{
	DDLC_ESCAPE_PLAN_FAILED;
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		fors(i, 1, n) cin >> a[i];
		int ans = 2 * n - 1;
		for(int len = 3; len <= 4; ++len){
			for(int l = 1; l + len - 1 <= n; ++l){
				if(len == 3 && check(l, l + 1, l + 2)) ans++;
				else if(len == 4 && (check(l, l + 1, l + 2) && check(l, l + 2, l + 3) && check(l + 1, l + 2, l + 3) && check(l, l + 1, l + 3))) ans++;
			}
		}
		cout << ans << endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值