Educational Codeforces Round 94 (Rated for Div. 2)

A. String Similarity

题目链接

点我跳转

题目大意

给定一个长度为 2 * n - 1 的字符串要 S

要求构造一个字符串 W 使得 W 与 S[1,n] , S[2,n+1] , ... , S[n,2*n-1] 相似

相似的定义 :如果一个字符串 A 与 一个字符串 B 至少有一个位置的字符相同 , 则 A、B相似

解题思路

令 W[i] 与 S[i , i + n - 1] 的第 i 位相同即可

#include<bits/stdc++.h>
using namespace std;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = 1 , n;
	cin >> T;
	while(T --)
	{
		string s , t = "";
		cin >> n >> s ;
		for(int i = 0 ; i < s.size() ; i += 2) t += s[i];
		cout << t << '\n';
	}
	return 0;
}

B. RPG Protagonist

题目链接

点我跳转

题目大意

你有一个容量为 P 的背包 , 你的伙伴有个容量为 F 的背包

现有 x 件物品 A , y 件物品 B , 物品 A 的体积为 S , 物品 B 的体积为 W

问你和你的伙伴最多能拿多少件物品

解题思路

枚举你拿物品 A 的数量 , 那么你还可以拿的 B 的数量也确定了

对于同伴优先拿体积小的物品即最优 , 枚举完输出最大值即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = 1;
	cin >> T;
	while(T --)
	{
		int p , f , x , y , s , w , ans = 0;
		cin >> p >> f >> x >> y >> s >> w;
		if(s > w) swap(s , w) , swap(x , y);
		for(int i = 0 ; i <= x ; i ++)
		{
			if(i * s > p) break;
			int j = min(y, (p - (i * s)) / w), k = min(x - i, f / s), l = min(y - j, (f - (s * k)) / w);
			ans = max(ans, i + j + k + l);
		}
		cout << ans << '\n';
	}
	return 0;
}

C. Binary String Reconstruction

题目链接

点我跳转

题目大意

字符串 w、s 只包含 01

给定一个 x , 若 w[i] = 1 , 则 s[i - x] 、s[i + x] = 1

现给出 s , 求 w

解题思路

对于 S[i] = 0 , W[i + x] 、W[i - x] 必定也为 0

然后对于 S[i] = 1 , 判断 W[i + x] 或 W[i - x] 是否可以为 1

若 S[i] = 1 , 且 W[i + X] 、W[i - X] 都必须为 0 , 则无法构造出 W

若对于所有的 S[i] 都可满足 W[i + X] 或 W[i - X] 可以为 1 , 则构造成功 , 输出 W

#include<bits/stdc++.h>
using namespace std; 
const int N = 2e5 + 10;
char s[N] , w[N];
int n , x , flag;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = 1;
	cin >> T;
	while(T --)
	{
		cin >> s + 1 >> x;
		n = strlen(s + 1) , flag = 0;
		for(int i = 1 ; i <= n ; i ++) w[i] = '#';
		for(int i = 1 ; i <= n ; i ++) if(s[i] == '0') 
		{
			if(i - x >= 1) w[i - x] = '0';
			if(i + x <= n) w[i + x] = '0'; 
		}
		for(int i = 1 ; i <= n ; i ++) if(s[i] == '1')
		{
			if(i - x >= 1)
			{
				if(w[i - x] == '#' || w[i - x] == '1') {w[i - x] = '1' ; continue ;}
			}
			if(i + x <= n) 
			{
				if(w[i + x] == '#' || w[i + x] == '1') {w[i + x] = '1' ; continue ;}
			}
			flag = 1 ; break ;
		}
		if(flag) cout << -1 << '\n';
		else
		{
			for(int i = 1 ; i <= n ; i ++) 
			{
				if(w[i] == '#') cout << 1;
				else cout << w[i];
			}
			cout << '\n';
		}
	}
	return 0;
}

D. Zigzags

题目链接

点我跳转

题目大意

给定一个长度为 n 的数组 A

问满足 1 <= I < J < K < L <= n , 且 aI = aK , aJ = aL 的四元组 (I , J , K , L) 有多少个

解题思路

简单分析一下 , 在看到 N <= 3000 时 , 首先可以想到的是枚举四元组的其中两个

那么就有以下六种方案

  1. 枚举 I J
  2. 枚举 I K
  3. 枚举 I L
  4. 枚举 J K
  5. 枚举 J L
  6. 枚举 L K

再根据 aI = aK , aJ = aL可以得到以下:

①、若我们选择枚举 I J , 则我们可以得到 aI、aJ、aK、aL,以及控制 I、J的大小关系 , 但是这样 K、L的区间就重了 , 因此我们还需要多枚举一个 K or L

②、若我们枚举 I K , 则我们可以得到 aI、aK,以及控制 I、J、K、L的大小关系 , 但 aJ 和 aL 的值我们就无法得知了 , 因此我们还需要多枚举一个 J or L

③、若我们枚举 I L , 问题同方案①
④、若我们枚举 J K , 则我们可以得到 aI、aJ、aK、aL,以及控制 I、J、K、L的大小关系 , 所有需要的信息都有了 , 因此我们枚举 J K即可

方案⑤、方案⑥的问题分别同 ②、①

因此我们枚举 J K , ans += 区间[1 , J - 1] 内 aK 的个数 * 区间[K +1 , n] 内 aL 的个数

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e3 + 10;
int sum[N][N] , a[N] , n;
int get(int l , int r , int x){
	return sum[r][x] - sum[l - 1][x];
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = 1;
	cin >> T;
	while(T --)
	{
		cin >> n;
		for(int i = 1 ; i <= n ; i ++) cin >> a[i];
		for(int i = 1 ; i <= n ; i ++)
		{
			for(int j = 1 ; j <= n ; j ++) sum[i][j] = sum[i - 1][j];
			sum[i][a[i]] ++ ;
		}
		int ans = 0;
		for(int j = 2 ; j <= n - 2 ; j ++) 
			for(int k = j + 1 ; k <= n - 1 ; k ++) ans += get(1 , j - 1 , a[k]) * get(k + 1 , n , a[j]);
		cout << ans << '\n';
		for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= n ; j ++) sum[i][j] = 0;
	} 
	return 0;
}

E. Clear the Multiset

题目链接

点我跳转

题目大意

给出了 N 个墙的高度,要求把这些墙都涂满。

每次可以刷一行或一列,问最少刷多少次可以将所有墙刷完。

解题思路

老原题了

要将区间 [L , R] 的墙刷完 , 可以执行若干次步骤

每次步骤有两种选则

1、选择一个区间横向不断刷直到改区间高度最低的墙被刷完

2、选择某面墙 , 竖着一次性把它刷完

因为 N <= 5000 , 所以很显然采用分治统计最优解

#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10;
int n , a[N];
int get(int st , int ed)
{
	int mi = 0x3f3f3f3f , res = 0;
	for(int i = st ; i <= ed ; i ++) mi = min(a[i] , mi);
	res += mi;
	for(int i = st ; i <= ed ; i ++) a[i] -= mi;
	int l = st , r = st;
	while(l <= ed)
	{
		
		while(!a[l] && l <= ed) l ++ ;
		if(l > ed) break ; 
		r = l + 1;
		while(a[r] && r <= ed) r ++ ;
		res += get(l , r - 1);
		l = r;
	}
	return min(ed - st + 1 , res);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	cin >> n;
	for(int i = 1 ; i <= n ; i ++) cin >> a[i];
	cout << get(1 , n) << '\n';
	return 0;
}
posted @ 2020-08-26 15:47  GsjzTle  阅读(205)  评论(0编辑  收藏  举报