其他分享
首页 > 其他分享> > Codeforces Round #715 (Div. 2) A ~ D

Codeforces Round #715 (Div. 2) A ~ D

作者:互联网

个人博客版:http://www.noobzyk.top/?p=692

A. Average Height

分析

堪比div3 A的水题

代码

/**
  * @file    :vsDebug2.cpp
  * @brief   :
  * @date    :2021-04-16
  * @Motto   :Love Sakurai Yamauchi Forever
  */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <deque>
#include <cmath>
#include <algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define int long long
const int inf = 0x3f3f3f3f;
typedef long long ll;
using namespace std;
const int maxn = 2005;
int main()
{
	IOS;
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		vector<int> odd, even;
        int x;
		for(int i = 0; i < n; ++i){
			cin >> x;
			if(x & 1) odd.push_back(x);
			else even.push_back(x);
		}
		for(int i = 0; i < odd.size(); ++i) cout << odd[i] << ' ';
		for(int i = 0; i < even.size(); ++i) cout << even[i] << ' ';
		cout << endl;
	}
	return 0;
}

B. TMT Document

题意

给一个只含有T,M的字符串,问是否可以分割成若干个不相交的“TMT"子序列。

例如,TMTMTT可以划分成两个TMT(TMTMTT).

分析

首先,为确保数据合法,保证T的总个数是M的两倍.

然后,从左往右看,保证字符串所有前缀都满足T的数目不小于M的,这样就能保证“TM”序列总是可以划分的。

由于是对称的,再从右往左看,保证“MT”序列总可以划分,即保证了“TMT"总可以划分。

代码

/**
  * @file    :vsDebug2.cpp
  * @brief   :
  * @date    :2021-04-16
  * @Motto   :Love Sakurai Yamauchi Forever
  */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <deque>
#include <cmath>
#include <algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define int long long
const int inf = 0x3f3f3f3f;
typedef long long ll;
using namespace std;
 
int main()
{
	IOS;
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		string s;
		cin >> s;
		int T = 0, M = 0;
		bool flag = 1;
		for(int i = 0; i < s.size(); ++i){
			if(s[i] == 'T') T++;
			else if(s[i] == 'M'){
				M++;
				if(T < M){
					flag = 0;
					break;
				}
			}
		}
		if(T != 2 * M) flag = 0;
		if(!flag){
			cout << "NO" << endl;
			continue;
		}
		T = 0, M = 0;
		for(int i = n - 1; i >= 0; --i){
			if(s[i] == 'T') T++;
			else if(s[i] == 'M'){
				M++;
				if(T < M){
					flag = 0;
					break;
				}
			}
		}
		if(!flag) cout << "NO" << endl;
		else cout << "YES" << endl;
	}
	return 0;
}

C.The Sports Festival

题意

给定一组数,现在将这些数按某种顺序加入。设置一个初始值为0的值 x x x.

每加入一个数, x x x加上当前加入的所有数的最大值-最小值。

问怎么排加入的顺序来保证最后得到的 x x x最小,输出最小 x x x即可。

分析

首先要贪心分析一波:

当序列中的数都是一样的时候, x x x每次都只能加0;如果不一样,保证尽量接近, x x x每次加的值也会较小。

所以,我们先将原输入序列排个序。

接下来是区间DP.

设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示区间 { i , j } \{i,j\} {i,j}得到的最小 x x x,则:
d p [ i ] [ j ] = m i n ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] ) + a [ j ] − a [ i ] dp[i][j]=min(dp[i+1][j], dp[i][j-1])+a[j]-a[i] dp[i][j]=min(dp[i+1][j],dp[i][j−1])+a[j]−a[i]
因为已经排好序,所以当前最大值减最小值就是 a [ j ] − a [ i ] a[j]-a[i] a[j]−a[i].

之后按长度动规, d p dp dp复杂度为 O ( n 2 ) O(n^2) O(n2),总复杂度为 O ( n 2 + n l o g n ) = O ( n 2 ) O(n^2+nlogn)=O(n^2) O(n2+nlogn)=O(n2).

代码

/**
  * @file    :vsDebug2.cpp
  * @brief   :
  * @date    :2021-04-16
  * @Motto   :Love Sakurai Yamauchi Forever
  */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <deque>
#include <cmath>
#include <algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
typedef long long ll;
using namespace std;
 
signed main()
{
	IOS;
		int sum = 0;
		int n;
		cin >> n;
		int a[n];
		for(int i = 0; i < n; ++i){
			cin >> a[i];
		}
		sort(a, a + n);
		int dp[n][n];
		memset(dp, 0, sizeof(dp));
		for(int l = 2; l <= n; ++l){
			for(int i = 0, j = i + l - 1; j < n; ++i, ++j){
					dp[i][j] = min(dp[i][j - 1], dp[i + 1][j]) + a[j] - a[i];
			}
		}
		
		cout << dp[0][n - 1] << endl;
		
	return 0;
}

D. Binary Literature

其他

CF官方的解法真的妙~~~~~~~~~~~~~~~~啊

题意

给定一个数字 n n n,然后给出3个长度为 2 n 2n 2n的01字符串,现在要你构造一个长度不超过 3 n 3n 3n的字符串,要求至少有2个给出的01串是这个字符串的子序列(不是子串!)

另外,可以证明,这样的构造总是存在的。

分析

三指针做法,初始依次指向各个01字符串的开头。另外,新建一个字符串 s s s.

由于为01字符串,故3个指针指向的位置至少有2个的字符是一样的,将这个字符加入 s s s,并将这两个指针右移一位,剩下的一个指针不动。

如果有一个指针 p p p移动到了终点,那么现在进一步分析:

/**
  * @file    :vsDebug2.cpp
  * @brief   :
  * @date    :2021-04-16
  * @Motto   :Love Sakurai Yamauchi Forever
  */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <deque>
#include <cmath>
#include <algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define int long long
const int inf = 0x3f3f3f3f;
typedef long long ll;
using namespace std;
int p[3] = {0};
string s[3];
int main()
{
	IOS;
	int t;
	cin >> t;
	while(t--)
	{
		memset(p, 0, sizeof(p));
		int n;
		cin >> n;
		string u;
		cin >> s[0] >> s[1] >> s[2];
		while(p[0] < 2 * n && p[1] < 2 * n && p[2] < 2 * n){
			if(s[0][p[0]] == s[1][p[1]]){
				u += s[0][p[0]];
				p[0]++, p[1]++;
			}
			else if(s[0][p[0]] == s[2][p[2]]){
				u += s[0][p[0]];
				p[0]++, p[2]++;
			}
			else if(s[1][p[1]] == s[2][p[2]]){
				u += s[1][p[1]];
				p[1]++, p[2]++;
			}
		}
		string u1, s1;
		if(p[0] == 2 * n){
			while(p[1] < 2 * n){
				u1 += s[1][p[1]++];
			}
			while(p[2] < 2 * n){
				s1 += s[2][p[2]++];
			}
		}
		else if(p[1] == 2 * n){
			while(p[0] < 2 * n){
				u1 += s[0][p[0]++];
			}
			while(p[2] < 2 * n){
				s1 += s[2][p[2]++];
			}
		}
		else if(p[2] == 2 * n){
			while(p[1] < 2 * n){
				u1 += s[1][p[1]++];
			}
			while(p[0] < 2 * n){
				s1 += s[0][p[0]++];
			}
		}
		if(u1.size() + u.size() <= 3 * n) cout << u + u1 << endl;
		else cout << u + s1 << endl;
	}
	return 0;
}

标签:int,715,Codeforces,long,cin,++,Div,include,dp
来源: https://blog.csdn.net/qq_39561693/article/details/115836776