Educational Codeforces Round 161 (Rated for Div. 2)(A - E)

比赛地址 :

https://codeforces.com/contest/1922

A. Tricky Template

直接根据题意就能够发现 :

遍历每一个位置 i : 如果能够发现 c[i]!=a[i] && c[i]!=b[i] , 就直接返回true;

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define lowbit(x) (x&(-x))
#define sz(a) (int)a.size()
#define pb push_back
#define all(a) a.begin(), a.end()
#define int long long
typedef long long LL;
const int mod = 1e9+7;
const int N = 2e5+10;

using namespace std;

inline void solve(){
	int n ; cin >> n ;
	string a,b,c;
	cin >>a>>b>>c;
	bool tag = false ;
	for(int i=0;i<n;i++){
		if(c[i]!=a[i] && c[i]!=b[i]){
			tag = true;
			break ;
		}
	}
	if(tag) cout << "Yes" <<endl;
	else cout << "No" <<endl;
}
 
signed main()
{
    IOS
    int _ = 1;
    cin >> _;
    while(_ --) solve();
    return 0;
}

B. Forming Triangles

B 题的话要用到组合数的思想 ,和 三角形的知识 ;

首先看题 : 对于每一条边都是2^ai,分析一下的话,如果三条边的长度都不相等的话,那么就一定不可能构造出一个三角形 ;

例如 分别为i-1 , i , i+1 的三个边的长度就是a = 2^i-1 , b = 2 ^ i , c = 2 ^ i + 1 , 那么无论如何都会出现 a + b < c 的情况,因为a < c-b = b , 如果间隔再取大一点的话,那就更不可能满足了;

有了以上分析之后,可以得出只有可能是等边或者等腰三角形满足题目条件 ;

那么就先排序,然后依据每个相等长度木棒数量len进行分析即可:

if(len>=3){//等边 
			ans += 1LL * (len) * (len-1) * (len-2) / 6 ;
		}
if(len>=2){// 等腰
			ans += 1LL * (len) * (len-1) / 2 * (i-1) ;
		}

详细请看代码 :

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define lowbit(x) (x&(-x))
#define sz(a) (int)a.size()
#define pb push_back
#define all(a) a.begin(), a.end()
#define int long long
typedef long long LL;
const int mod = 1e9 + 7;
const int N = 3e5 + 10;

using namespace std;

int a[N] ;

inline void solve() {
	int n ; cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	if(n<3){
		cout << 0 << endl;
		return ;
	}
	sort(a+1,a+1+n) ;
	// abb
	int ans = 0 ;
	for(int i=1;i<=n;i++){
		int j = i + 1;
		while(j<=n && a[j]==a[i]) j++;
		int len = j - i ;
		if(len>=3){//等边 
			ans += 1LL * (len) * (len-1) * (len-2) / 6 ;
		}
		if(len>=2){
			ans += 1LL * (len) * (len-1) / 2 * (i-1) ;
		}
		i = j - 1 ;
	}
	
	cout << ans << endl;
	return ;
}

signed main()
{
    IOS
    int _ = 1;
    cin >> _;
    while (_--) solve();
    return 0;
}

C. Closest Cities

此题采用类似于前缀和的思想来解决,先预处理好两个数组st,ed,其中st[i]表示由1城市到i城市的最小花费,ed[i]表示从n城市到i城市的最小花费;

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 1e5 + 10 ;
typedef long long LL ;
LL a[N] , st[N] , ed[N];

void solve() {
	int n ; cin >> n ;
	for(int i=1;i<=n;i++) cin >> a[i] ;
	// st[i]表示从1到i的最小花费 
	st[1] = ed[n] = 0 ;
	st[2] = 1 ;// 1 到 2 城市 一定是 1 
	for(int i=3;i<=n;i++){
		//  i-1 到 i   
		int l = a[i-1] - a[i-2];
		int r = a[i] - a[i-1];
		if(l<r) st[i] = st[i-1] + r ;
		else st[i] = st[i-1] + 1 ;
	} 
	ed[n-1] = 1;
	for(int i=n-2;i>=1;i--){
		// i+1 到 i 
		int l = a[i+1] - a[i];
		int r = a[i+2] - a[i+1];
		if(l<r) ed[i] = ed[i+1] + 1;
		else ed[i] = ed[i+1] + l;
	}
    int m ; cin >> m;
    while(m--){
      int x,y;
      cin >> x >> y;
      if(x < y) cout << st[y] - st[x] << endl;
      else cout << ed[y] - ed[x] << endl;
    }
    return ;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int _ = 1;
    cin >> _;
    while (_--) solve();
    return 0;
}

D . Berserk Monsters

首先我们可以看出,当所有怪物在一轮中全部活了下来,那么显然,下一轮还是所有怪物都活着,那么实际上也说明了一个问题,只有上一轮死去了怪物,死去的怪物的左右会改变,也就是它们受到的伤害会变得不一样,产生新的怪物;

我们需要注意,只有上轮怪物死掉得左右需要再次算一遍;

这样得操作很类似于一个链表 , o(1) ;

我们可以记录左右 , 然后模拟链表 ;

当然我们可以简单一点,我们可以搞一个set,用于计算目前得左右点,O(logn)

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define lowbit(x) (x&(-x))
#define sz(a) (int)a.size()
#define pb push_back
#define all(a) a.begin(), a.end()
#define int long long
typedef long long LL;
const int mod = 1e9+7;
const int N = 2e5+10;

using namespace std;


inline void solve(){
	int n ; cin >> n ;
	vector<int> a(n+1);// 记录攻击
	vector<int> d(n+1);// 记录防御 
	vector<int> l(n+1);// 记录左边 
	vector<int> r(n+1);// 记录右边 
	for(int i=1;i<=n;i++) cin >> a[i-1] ;
	for(int i=1;i<=n;i++) cin >> d[i-1] ;
	a[n] = 0 ;// 创造一个新点 , 不算人 , 也没有攻击力
	d[n] = 0 ;//  
	int de[n+1] ;// de数组 : 记录一个点是否死掉,防止重复计算
	for(int i=0;i<=n;i++){
		l[i] = n ;
		r[i] = n ;
		de[i] = 0 ;
	}
	for(int i=0;i<n;i++){// 初始化 链表 的 左右连接
		if(i-1>=0) l[i] = i - 1 ;
		if(i+1<=n-1) r[i] = i + 1 ;
	}
	queue<int> q ;// 写一个队列 , 记录哪些点可能被删除 ; 
	for(int i=0;i<n;i++){
		q.push(i);
	}
	vector<int> ans(n);
	int cnt = 0 ;
	while(1){
		int len = q.size() ;
		int zhi = 0 ; // 记录这轮死了多少怪物 
		vector<int> drr ; // 记录目前删掉哪些点 , 后面会进行链表的从新连接
		while(len--){
			int z = q.front();
			q.pop() ;
			if(z==n) continue ;
			if(de[z]>=1) continue;
			if(a[l[z]]+a[r[z]]>d[z]){// 当左右能够杀死这个点 
				drr.push_back(z);// 加到本轮能够删除的点 
				de[z]++;// 已经死掉的标记 
				zhi++;
			}
		} 
		if(zhi==0) break;// 如果没点死掉,那么就不用再算了 
		set<int> st ;// 找到目前可能还会被杀死的怪物 
		for(auto x : drr){
			if(l[x]>=0){
				r[l[x]] = r[x];// 链表的连接 
				if(de[l[x]]>=1) continue;
				else st.insert(l[x]);// 如果有怪物没死 
			}
			if(r[x]<=n-1){
				l[r[x]] = l[x] ;// 链表的连接
				if(de[r[x]]>=1) continue;
				else//同理
					st.insert(r[x]); 
			}
		}
		for(auto x : st){
			q.push(x);// 添加进队列 , 新的可能被杀死的怪物 
		}
		ans[cnt++] = zhi;// 记录一下本轮答案 
	}
	for(int i=cnt ;i<n;i++) ans[i] = 0 ;
	for(int i=0;i<n;i++) cout << ans[i] << " " ;
	cout << endl ;
	return ;
}
 
signed main()
{
    IOS
    int _ = 1;
    cin >> _;
    while(_ --) solve();
    return 0;
}

E. Increasing Subsequences

思路如下 :

// 构造 , 位运算

// 设数组 a 有 x 个递增的子序列

// 在数组的末尾添加一个新的最小值,ans = x + 1 ;

// 在数组末尾添加一个新的最大值,新数组中的ans = 2 * x ;

// 那么分奇偶 , 使用递归函数f(x) , 他返回正好有x个递归子序列的数组。

// 对于奇数 x : f(x) = f(x-1) + min,这里+表示向数组末尾添加一个最小的元素

// 对于偶数 x : f(x) = f(x/2) + max

// 估计元素数量 :

代码 :

#include <bits/stdc++.h>
 
using namespace std;
 
vector<int> f(long long x) {
  vector<int> res;
  if (x == 2) {
  	res.push_back(0);
  } else if (x & 1) {
    res = f(x - 1);
    res.push_back(*min_element(res.begin(), res.end()) - 1);
  } else {
    res = f(x / 2);
    res.push_back(*max_element(res.begin(), res.end()) + 1);
  }
  return res;
}
 
int main() {
  int t;
  cin >> t;
  while (t--) {
    long long x;
    cin >> x;
    auto ans = f(x);
    cout << ans.size() << '\n';
    for (int i : ans) cout << i << ' ';
    cout << '\n';
  }
}
相关推荐
王老师青少年编程5 分钟前
gesp(二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
数据结构·c++·算法·gesp·csp·信奥赛
robin_suli31 分钟前
动态规划子序列问题系列一>等差序列划分II
算法·动态规划
机器视觉知识推荐、就业指导1 小时前
C++设计模式:解释器模式(简单的数学表达式解析器)
c++·设计模式·解释器模式
海螺姑娘的小魏1 小时前
Effective C++ 条款 16:成对使用 `new` 和 `delete` 时要采取相同形式
开发语言·c++
cxylay1 小时前
自适应滤波算法分类及详细介绍
算法·分类·自适应滤波算法·自适应滤波·主动噪声控制·anc
茶猫_1 小时前
力扣面试题 - 40 迷路的机器人 C语言解法
c语言·数据结构·算法·leetcode·机器人·深度优先
轻浮j2 小时前
Sentinel底层原理以及使用算法
java·算法·sentinel
Abelard_2 小时前
LeetCode--347.前k个高频元素(使用优先队列解决)
java·算法·leetcode
小猪写代码2 小时前
C语言:递归函数(新增)
算法·c#
点云SLAM2 小时前
C++创建文件夹和文件夹下相关操作
开发语言·c++·算法