牛客周赛 Round 82(思维、差分、树状数组、大根堆、前后缀、递归)

牛客周赛 Round 82(思维、差分、树状数组、大根堆、前后缀、递归)

A. 夹心饼干

语法基础题

#include<bits/stdc++.h>
using namespace std;

int main(){
		
	string s;
	cin >> s;
	cout << (s[0] == s[2] ? "YES" : "NO") << endl;

	return 0;
}

B. C. 食堂大作战(思维)

显然,只要没有两个窗口同时关门,即合法方案。

对于方案,按照关门时间排序,依次输出即可。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;

pair<int, int> a[maxn];

int main(){
		
	int n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i].first;
        a[i].second = i;
    } 
    
    sort(a+1, a+1+n);
    
    int flag = 1;
    for(int i = 1; i <= n; i++){
        if(a[i].first == a[i-1].first){
            flag = 0;
            break;
        }
    }
    if(flag){
        cout << "YES" << endl;
    }
    else cout << "NO" << endl;
    
	return 0;
}

D. 小苯的排列计数(差分、树状数组)

对于样例:

10

7 7 7 5 5 1 1 1 1 1 1

首先,标黄色的元素的值是确定的。

其次,我们依次来看:

  1. 72,在此处,可以选择 8,9,10。即,有三种选择。(这里表示第二个 7,其他相同形式同理)
  2. 73,在此处,可以选择 8,9,10。但是,这时已经在 72处使用过一个元素,还有两种选择可用。
  3. 52,在此处,可以选择 6,8,9,10。但是,这时已经在 72 和 73 处使用过两个元素,还有两种选择可用。
  4. 依次类推…

对于一个方案,在某元素 x:

  1. 如果第一次出现时,该元素在只能在此处,在此处贡献一种组合的可能。
  2. 如果元素 x 不是第一次出现时:
    • 如有大于该元素的选择,可选择元素的个数等于此处贡献的组合。
    • 如没有大于该元素的选择,则方案不合法。

使用差分和树状数组配合,即可实现,求[x, n] 中的可用元素个数。


#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 1e6 + 5;
const ll mod = 998244353;

ll a[maxn], tree[maxn];

int lowbit(int x){
    return x & (-x);
}

void add(int i, int value){
    while(i < maxn){
        tree[i] += value;
        i += lowbit(i);
    }
}

int sum(int i){
    int res = 0;
    while(i > 0){
        res += tree[i];
        i -= lowbit(i);
    }
    return res;
}

int main(){
    
    int ncase;
    cin >> ncase;
    
    while(ncase--){
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        
        for(int i = 1; i <= n; i++) tree[i] = 0;
        for(int i = 1; i <= n; i++) add(i, 1);
        
        ll res = 1;
        for(int i = 1; i <= n; i++){
            if(a[i] != a[i-1]){
                if(a[i] > a[i-1]  && i != 1){
                    res = 0;
                    break;
                }
                add(a[i], -1);
            }
            else{
                int cnt = sum(n) - sum(a[i]);	// 差分
                if(cnt == 0){
                    res = 0;
                    break;
                }
                else{
                    res = res * cnt % mod;
                    add(a[i]+1, -1);
                }
            }
        }
        cout << res << endl;
    }

    
	return 0;
}

E. 和+和(大根堆,前缀和)

题意等价于:选一个 x,在 a[1,x] 中选 m 个最小的数,在 b[x+1, n] 中选 m 个最小的数,使得选出的数sum最小。

枚举所有可能的 x,只要能 O(1) 或者 O(log(n)) 求出 a[1,x] 中 m 个最小的数的和,即可。


对于a数组,维护一个大小为 m 的大根堆,即前 i 个元素中最小的 m 个元素。

依次遍历a数组,插入新值a[i],删除最大的元素,维护sum,维护前缀min即可。


对于 b 数组,逆序遍历,操作同上。


#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 2e5 + 5;

ll a[maxn], b[maxn];
ll pre[maxn], suf[maxn];

priority_queue<int> qu;

int main(){
    
    int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) cin >> b[i];
	
	ll sum = 0;
	for(int i = 1; i <= n; i++){
		sum += a[i];
		qu.push(a[i]);
		if(i > m){
			sum -= qu.top();
			qu.pop();			
		}
		pre[i] = sum;
	} 
	
	sum = 0;
	while(!qu.empty()) qu.pop();
	
	for(int i = 1; i <= n; i++){
		sum += b[n-i+1];
		qu.push(b[n-i+1]);
		if(i > m){
			sum -= qu.top();
			qu.pop();			
		}
		suf[n-i+1] = sum;
	}
	
	ll res = 2e9;
	for(int i = m; i+m-1 < n; i++){
		res = min(res, pre[i] + suf[i+1]);
	}
	cout << res << endl;
    
	return 0;
}

F. 怎么写线性SPJ (思维、递归)

手搓几个样例后,容易想到一个事实:

令 mid = ( l + r ) / 2,如果 a[mid] 是一个 “唯一元素”,接下来,只需要考虑 (l, mid-1) 和 (mid+1, r) 即可。

用相同的思路处理(l, mid-1) 和 (mid+1, r),直到区间大小为 1。(递归)

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 2e5 + 5;

int a[maxn];

void dfs(int l, int r, int num){
	if(l > r) return; 
	int mid = l + r >> 1;
	a[mid] = num;
	dfs(l, mid-1, num+1);
	dfs(mid+1, r, num+1);
}

int main(){
    
    int n;
	cin >> n;
	
	dfs(1, n, 1); 
	
	set<int> s;
	for(int i = 1; i <= n; i++) s.insert(a[i]);
	cout << s.size() << endl;
	for(int i = 1; i <= n; i++) cout << a[i] << " ";
    
	return 0;
}
关于牛客Round 83 的具体题目和解答,目并未提供直接的引用支持。然而,可以基于以往的经验以及类似的周赛模式来推测可能涉及的内容结构。 通常情况下,牛客周赛会包含多个不同难度级别的题目,从简单的签到题(A 类型)到较难的挑战性问题(E 或 F 类型)。以下是根据已有经验构建的一般框架: ### 牛客周赛 Round 83 可能的主题 #### A - 签到题 这类题目通常是简单算法的应用或者基础逻辑判断。例如: ```python def solve_a(): n = int(input()) result = sum(range(1, n + 1)) # 计算N项自然数之和 print(result) solve_a() ``` 此部分无需深入解析,主要考察参赛者的基础编程能力[^1]。 #### B - 中等难度题 此类题目可能会涉及到数组操作、字符串处理或基本数据结构应用。比如给定一段文字统计特定字符频率的问题。 ```python from collections import Counter def solve_b(): s = input().strip() counter = Counter(s) most_common_char, count = counter.most_common(1)[0] print(most_common_char, count) solve_b() ``` 上述代码片段展示了如何利用Python内置库快速解决常见计数类问题[^2]。 #### C/D/E/F 更高阶挑战 这些更复杂的任务往往需要运用高级技巧如动态规划(DP),图论(Graph Theory)或者其他专门领域知识才能有效完成。由于缺乏具体的Round 83资料,这里仅给出一个假设性的例子有关最短路径寻找: ```python import heapq INF = float('inf') def dijkstra(graph, start_node): distances = {node: INF for node in graph} distances[start_node] = 0 priority_queue = [(0, start_node)] while priority_queue: current_distance, current_vertex = heapq.heappop(priority_queue) if current_distance > distances[current_vertex]: continue for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances graph_example = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2, 'D': 5}, 'C': {'A': 4, 'B': 2, 'D': 1}, 'D': {'B': 5, 'C': 1} } print(dijkstra(graph_example, 'A')) ``` 这段程序实现了经典的迪杰斯特拉算法用于求解加权无向图中的单源最短路径问题[^3]. 尽管无法确切知道每道实际考题是什么样子,但通过以上介绍应该能够帮助理解一般竞赛形式下的潜在考点及其解决方案设计方法.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值