Educational Codeforces Round 91 (Rated for Div. 2)A、B、C、D题解

目录

 

1380A. Three Indices

1380B. Universal Solution

1380C. Create The Teams

1380D. Berserk And Fireball


1380A. Three Indices

题意:给定一个长度为N的排列,问能否找到三个坐标 ij ,k 满足条件:1\leq i<j<k\leq np_i < p_j and p_j>p_k

思路:随便做。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-13 08:28
 *Link: 
 *-------------------------------*/
#pragma GCC diagnostic error "-std=c++11"
#include
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n;
		scanf("%d", &n);
		vector a(n);
		for(int i = 0; i < n; ++i){
			scanf("%d", &a[i].fi);
			a[i].se = i + 1;
		}
		sort(a.begin(), a.end());
		bool flag = 0;
		for(int i = n - 1; i >= 2; --i){
			if(a[i].se != n && a[i].se != 1){
				int l, r;
				l = r = 0;
				for(int j = i - 1; j >= 0; --j){
					if(a[j].se < a[i].se) l = a[j].se;
					if(a[j].se > a[i].se) r = a[j].se;
				}
				if(l && r){
					printf("YES\n");
					printf("%d %d %d\n", l, a[i].se, r);
					flag = 1;
					break;
				}
			}
		}
		if(!flag) printf("NO\n");
	}
	return 0;
}

1380B. Universal Solution

题意:给一个只包含“R”,”S“,”P“的字符串,分别代表石头,剪刀、布,要求找到一个字符串,使得不管从哪个位置开始和给定字符串一一匹配之后获胜的平均局数最多。

思路:平均局数最大也就是获胜总局数最大,因为匹配有n种方法,所以实际上答案字符串必定是全部一样的最优。想想在字符串给定的情况下,石头剪刀布分别能够获胜的局数就确定了,这时候如果选择了两个不同的字符作为答案,较少的那个字符替换成较多的那个字符很明显更优,因此只要知道哪个获胜次数最多就好。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-13 08:28
 *Link: 
 *-------------------------------*/
#pragma GCC diagnostic error "-std=c++11"
#include
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		string s;
		cin >> s;
		map mp;
		mp['R'] = 'P';
		mp['P'] = 'S';
		mp['S'] = 'R';
		map cnt;
		int Max = 0; char x;
		for(int i = 0; i < s.length(); ++i){
			cnt[s[i]]++;
			if(cnt[s[i]] > Max) Max = cnt[s[i]], x = s[i];
		}
		for(int i = 0; i < s.length(); ++i) printf("%c", mp[x]);
		printf("\n");
	}
	return 0;
}

1380C. Create The Teams

题意:有N个人要分组,每个人若有组则只参加一组,每个人有技能值 a_i ,组队要求为:组员人数与组员中最低技能值的乘积要不小于x。问最多可以分几组。

思路:要分最多组肯定是每组的人数越少越好。当人数越少时,为了满足限制,则需要组内最低技能值高,因此从大到小遍历所有人,判断当前人数和最低技能值的乘积是否够组成一个组。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-13 08:28
 *Link: 
 *-------------------------------*/
#pragma GCC diagnostic error "-std=c++11"
#include
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;

bool cmp(int x, int y){return x > y;}

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n;
		scanf("%d", &n);
		LL x;
		scanf(" %lld", &x);
		vector a(n);
		for(LL &i : a) scanf("%d", &i);
		sort(a.begin(), a.end(), cmp);
		int ans = 0;
		for(int i = 0; i < n; ){
			int l, r;
			l = r = i;
			LL tmp = 1;
			int cnt = 1;
			int Min = a[r];
			while(r < n){
				tmp = Min * cnt;
				if(tmp >= x) break;
				cnt++;
				r++;
				Min = a[r];
			}
			if(tmp >= x) ans++;
			i = r + 1;
			//printf("i = %d\n", i);
		}
		printf("%d\n", ans);
	}
	return 0;
}

1380D. Berserk And Fireball

题意:有N个战士,每个战士有武力值 A_i ,且每个战士的武力值都不相同。现在要留下M个战士,每个战士的武力值为B_i,剔除战士的方法只有两种:第一种可以花费X个mana然后剔除连续K个战士;第二种可以花费Y个mana然后选择两个相邻的战士,剔除掉武力值较小的战士。问最少花费多少mana就可以得到要求的M个战士。

思路:首先判断M个战士的出现顺序是否和N个战士的出现顺序一样,如果不一样则不行。在满足以上条件后记录每个留下的战士的坐标,然后计算剔除相邻坐标间的区间内的所有战士的花费。但是在计算花费时,若发现区间内的最大武力值大于区间左右两边留下战士的武力值且没有办法使用第一种方法剔除这个战士,则无法达成要求。

不是坑点的坑点:输入是X,K,Y,我下意识一直认为是X,Y,K,查了好久。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-13 08:28
 *Link: 
 *-------------------------------*/
#pragma GCC diagnostic error "-std=c++11"
#include
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair 
using namespace std;
const int maxn = 1e5 + 5;

LL x, y, k;
int n, m;
vector a, pos, b, remain;

bool cal(int l, int r, LL &ans){
	l++, r--;
	if(l > r) return 1;
	//printf("l = %d, r = %d\n", l, r);
	int cnt = r - l + 1;
	int Max = 0;
	for(int i = l; i <= r; ++i) Max = max(Max, a[i]);
	if(cnt == 0) return 1;
	bool deal = 0;
	if(l > 0 && a[l - 1] > Max) deal = 1;
	if(r < n - 1 && a[r + 1] > Max) deal = 1;
	if(cnt < k && !deal) return 0;
	int need = cnt % k;
	ans += need * y;
	cnt -= need;
	if(y * k >= x) ans += cnt / k * x;
	else if(deal) ans += cnt * y;
	else ans += (cnt - k) * y + x;//deal == 0, 需要一次连续消除操作消掉Max
	return 1;
}

int main(){
	scanf("%d %d", &n, &m);
	scanf("%lld %lld %lld", &x, &k, &y);
	int cnt = 0;
	a.resize(n);
	pos.resize(n + 1);
	b.resize(m);
	for(int &i : a) scanf("%d", &i), pos[i] = cnt++;
	int Max = -1;
	bool flag = 1;
	for(int &i : b){
		scanf("%d", &i);
		remain.pb(pos[i]);
		if(remain.back() < Max) flag = 0;
		Max = remain.back();
	}
	if(!flag) return printf("-1\n"), 0;
	LL ans = 0;
	flag = cal(-1, remain.front(), ans);
	if(!flag) return printf("-1\n"), 0;
	for(int i = 0; i < remain.size() - 1; ++i){
		flag = cal(remain[i], remain[i + 1], ans);
		if(!flag) return printf("-1\n"), 0;
	}
	flag = cal(remain.back(), n, ans);
	if(!flag) return printf("-1\n"), 0;
	printf("%lld\n", ans);
	return 0;
}

 

你可能感兴趣的:(Codeforces比赛题解)