Codeforces Edu Round #94 (CF1400)

掉了点分

A:

给定长度为\(2n-1\)的01字符串\(str\),求长度为\(n\)的字符串\(ans\),使得\(ans \sim str\)

定义字符串\(a \sim b\)时,有\(i\)满足\(a_i = b_i\)


一道ca大水题,有两种解法:

  1.  /*
     	ID: Loxilante
     	Time: 2020/08/27
     	Prog: CF1400A-1
     	Lang: cpp
     */
     #ifdef ONLINE_JUDGE
     #pragma GCC optimize("O3")
     #endif
     #include <bits/extc++.h>
     #define rep(i, l, r) for(int i = l; i < r; i++)
     #define hrp(i, l, r) for(int i = l; i <= r; i++)
     #define rev(i, r, l) for(int i = r; i >= l; i--)
     #define ms(n, t) memset(n, t, sizeof(n))
     #define pb push_back
     #define int ll
     #ifndef JOEON
     #define D(...) 97
     #endif
     using namespace std;
     typedef long long ll;
     typedef pair<int, int> pii;
     template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
     signed main(void)
     {
     	clock_t Begin = clock();
     
     	#ifdef JOEON
     //		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
     //		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
     	#endif
     	
     	ios::sync_with_stdio(false);
     	cin.tie(0);
     	
     	int T = next();
     	
     	clock_t InputFinished = clock();
     	
     	while(T--)
     	{
     		int n = next();
     		string str = next<string>();
     		rep(i, 0, n) cout<<str[n-1];
     		cout<<endl;
     	}
     	
     	clock_t End = clock();
     	
     	D((double)(End-Begin)/CLOCKS_PER_SEC);
     	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
     	
     	return 0;
     }
    
  2.  /*
     	ID: Loxilante
     	Time: 2020/08/25
     	Prog: CF1400A
     	Lang: cpp
     */
     #ifdef ONLINE_JUDGE
     #pragma GCC optimize("O3")
     #endif
     #include <bits/extc++.h>
     #define rep(i, l, r) for(int i = l; i < r; i++)
     #define hrp(i, l, r) for(int i = l; i <= r; i++)
     #define rev(i, r, l) for(int i = r; i >= l; i--)
     #define ms(n, t) memset(n, t, sizeof(n))
     #define pb push_back
     #define int ll
     #ifndef JOEON
     #define D(...) 97
     #endif
     using namespace std;
     typedef long long ll;
     typedef pair<int, int> pii;
     template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
     signed main(void)
     {
     	clock_t Begin = clock();
     
     	#ifdef JOEON
     //		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
     //		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
     	#endif
     	
     	ios::sync_with_stdio(false);
     	cin.tie(0);
     	
     	int T = next();
     	
     	clock_t InputFinished = clock();
     	
     	while(T--)
     	{
     		int l = next();
     		string str = next<string>();
     		for(int i = 0; i < str.length(); i += 2) cout<<str[i];
     
     		cout<<endl;
     	}
     	
     	clock_t End = clock();
     	
     	D((double)(End-Begin)/CLOCKS_PER_SEC);
     	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
     	
     	return 0;
     }
     
    

读者自证不难。



B:

你和随从分别能承重\(p, f\),现有\(cnt_s\)把剑和\(cnt_w\)把斧头,剑重\(s\),斧重\(w\),求最多能拿走多少武器。


考场上花一个小时打\(O(1)\)算法,先\(\color{red}{PigeonGuGuGu}\)着。

下面来考虑\(O(cnts)\)的做法:

假设\(s <= w\),也就是剑比斧重。

枚举自己最多带的剑的数量,算出能带斧的数量。

让随从带尽可能多的剑,如果带完了再带斧头。

Code:

/*
	ID: Loxilante
	Time: 2020/08/27
	Prog: CF1400B
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
//		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T = next<int>();
	
	clock_t InputFinished = clock();
	
	while(T--)
	{
		int y, f, cnts, cntw, s, w, ans = 0;
		cin>>y>>f>>cnts>>cntw>>s>>w;

		if (s > w) swap(cnts, cntw), swap(s, w);

		hrp(takeSword, 0, cnts) 
		{
			if (takeSword*s > y) break;

			int Y = y, F = f, ret = takeSword;
			Y -= takeSword*s; // i take sword

			int takeSword2 = min(F/s, cnts-takeSword); // follower take sword
			ret += takeSword2;
			F -= takeSword2*s;

			ret += min(cntw, Y/w+F/w); // take war axe

			ans = max(ans, ret);
		}
		cout<<ans<<endl;
	}
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}
/*
3
33 27
6 10
5 6
100 200
10 10
5 5
1 19
1 3
19 5
 */


C:

考场上读假题,罚时杠杠哒


给定整数\(x\)和字符串\(str\)\(str_i\)等于\(1\)当且仅当\(ans_{i+x}\)\(ans_{i-x}\)等于\(0\),求字符串\(ans\)


1500的ca,对于这种ca我们可以直接口胡个greedy水过:

\(str_i\)等于0时,我们让\(ans_{i \pm x} = 0\)反正没有limit随便瞎搞,不过只有这些这题就配不上1500啦,难点还有\(-1\)

不过这也很好操作,遍历\(ans\),然后判断是否合法,也就是\(str_i = 1\)时判断\(ans_{i \pm x}\)是否等于0,如果等于就输出\(-1\)1500的ca就是这么好水

Code:

/*
	ID: Loxilante
	Time: 2020/08/26
	Prog: CF1400C
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
//		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T = next();
	
	clock_t InputFinished = clock();
	
	while(T--)
	{
		string str = next<string>();
		int x = next();

		auto in = [=](const int& e)
		{
			return 0 <= e && e < str.length();
		};

		string ans;
		rep(i, 0, str.length()) ans += '1';
		rep(i, 0, str.length())
		{
			if (str[i] == '0')
			{
				int a = i-x, b = i+x;
				if (in(a)) ans[i-x] = '0';
				if (in(b)) ans[i+x] = '0';
			}
		}
		bool N = 1;
		rep(i, 0, str.size())
		{
			
			if (str[i] == '1')
			{
				bool no = 1;
				int a = i-x, b = i+x;
				if (in(a) && ans[a] == '1') no = 0;
				if (in(b) && ans[b] == '1') no = 0;
				if (no) {N = 0; break;}
			}
			
		}
		if (!N) cout<<-1<<endl;
		else cout<<ans<<endl;
	}
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}


D:

超级1900大水题,可以用超级ez的dp水过,勉强算个dp吧


给定数列\(w\),求满足\(w_i == w_k \&\& w_j == w_l (i < j < k < l)\)的个数。


考虑到\(n <= 3000\),可以用\(O(n^2)\)的暴力枚举。

枚举谁呢? \(i, j\) ?不妥,\(w_k\)\(w_l\)难求。\(etc.\)。感性推断,理性发现,只有枚举\(w_k\)\(w_j\),这样\(w_i\)\(w_l\)比较容易知道,也好写。

思路很简单:开一个\(pr\)前缀数组和\(suf\)后缀数组,\(pr_{i,j}\)代表指针i之前等于\(j\)的个数,\(suf_{i,j}\)代表指针i后等于\(j\)的个数,这大概也许应该是个dp吧,既然是dp,就得有个像样的转移方程,于是:

\(pr_{i, j} = pr_{i-1, j} + (j == w[i])\)

\(suf_{i, j} = suf_{i+1, j} + (j == w[i])\)


Code:

/*
	ID: Loxilante
	Time: 2020/08/26
	Prog: CF1400D
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 3e3+50;
int pr[U][U], suf[U][U], w[U];
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
//		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T = next();
	
	clock_t InputFinished = clock();
	
	while(T--)
	{
		int n = next(), ans = 0;
		rep(i, 0, n) cin>>w[i];

		ms(pr, 0);
		ms(suf, 0);

		rep(i, 0, n)
		{
			if (i) hrp(j, 0, n) pr[i][j] = pr[i-1][j];
			pr[i][w[i]]++;
		}

		rev(i, n-1, 0)
		{
			if (i != n-1) hrp(j, 0, n) suf[i][j] = suf[i+1][j];
			suf[i][w[i]]++;
		}

		rep(j, 1, n-2) rep(k, j+1, n-1) ans += pr[j-1][w[k]]*suf[k+1][w[j]];

		cout<<ans<<endl;
	}
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}
/*
Example
inputCopy
2
5
2 2 2 2 2
6
1 3 3 1 2 3
outputCopy
5
2
 */

然后我们发现,这个代码跑了1700ms,用了145000kb,大概是140mb,如果是128mb就要mle了,这时候我们可以压掉一个数组,把 \(suf\) 数组去掉,用类似前缀和的思想用大减小,这样就只有72000kb,也就是70mb。

Code:

/*
	ID: Loxilante
	Time: 2020/08/26
	Prog: CF1400D
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 3e3+50;
int pr[U][U], w[U];
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
//		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int T = next();
	
	clock_t InputFinished = clock();
	
	while(T--)
	{
		int n = next(), ans = 0;
		rep(i, 0, n) cin>>w[i];

		ms(pr, 0);

		rep(i, 0, n)
		{
			if (i) hrp(j, 0, n) pr[i][j] = pr[i-1][j];
			pr[i][w[i]]++;
		}

		rep(j, 1, n-2) rep(k, j+1, n-1) ans += pr[j-1][w[k]]*(pr[n-1][w[j]]-pr[k][w[j]]);

		cout<<ans<<endl;
	}
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}
/*
Example
inputCopy
2
5
2 2 2 2 2
6
1 3 3 1 2 3
outputCopy
5
2
 */


E:

sharbee重题


给定一个数列 \(w\),支持以下操作:

  1. \([l, r]\)中的元素自减\(1\).
  2. \(w_x\)的元素自减\(t\).

求最少的操作次数,使数列w变为\(0\)


先看题目,仔细一瞧,满足大问题分解成小问题的性质,这时候有两种选择,一是分治,二是dp,我选择分治,因为dp感觉有点难(

然后考虑分治函数,把一个大序列分解成左,右两个小序列,然后分别求解。

最后设计函数参数,首先begin, end是必不可少哒,其次我还设置了一个height,表示父问题中最小的元素的值。

Code:

/*
	ID: Loxilante
	Time: 2019/10/07
	Prog: CF1400E
	Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 5e3+50;
int w[U];
inline int solve(int begin, int end, int height) // [, )
{
	if (begin >= end) return 0;
	int mid = min_element(w+begin, w+end)-w, ans; // 找到最小元素然后分治
	ans = min(end-begin, solve(begin, mid, w[mid])+solve(mid+1, end, w[mid])+w[mid]-height);
    // end-begin表示把每个元素都清0的个数
	return ans;
}
signed main(void)
{
	clock_t Begin = clock();

	#ifdef JOEON
//		freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
//		freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
	#endif
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n = next();
	rep(i, 0, n) cin>>w[i];
	
	clock_t InputFinished = clock();
	
	cout<<solve(0, n, 0)<<endl;
	
	clock_t End = clock();
	
	D((double)(End-Begin)/CLOCKS_PER_SEC);
	D((double)(End-InputFinished)/CLOCKS_PER_SEC);
	
	return 0;
}

F和G 一个要用AC自动机,一个要用容斥,懒得写了(

posted @ 2020-08-28 02:27  Loxilante  阅读(162)  评论(1编辑  收藏  举报