百度松果菁英班–oj赛(第三次)
一、小码哥处理订单
**题目:**假期快到了,小码哥在宾馆打暑假工。
小码哥需要处理接下来n天的住房信息,其中第i天宾馆有ri个房间可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示需要从第sj天到第tj天住房(包括第sj天和第tj天),每天需要出租dj个房间。
宾馆入住是先到先得,也就是说,小码哥按照订单给到的先后顺序来进行处理。如果在分配的过程中遇到一份订单使从第sj天到第tj天中有至少一天剩余的房间数量不足dj个,则需要停止工作,通知当前申请人修改订单。
由于到了假期,宾馆入住人数很多,小码哥需要知道,是否会有订单无法完全满足。如果有,小码哥需要通知修改的是哪个订单。他真的太累了,请你编程帮小码哥解决问题。
/**
输入格式:第一行包含两个正整数n,m,表示天数和订单的数量;
第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的房间数量,影响到所有需要在这天租借的订单;
接下来有m行,表示先后给到的订单。每行包含三个正整数dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。
每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号,且申请人编号范围为1到m,与订单号一样。
输出格式:如果所有订单均可满足,则输出只有一行,包含一个整数0,否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。
样例1 输入:4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
输出:-1
2
备注
对于100%的数据,有1≤n, m ≤10^6,0≤ri≤10^9,0<dj≤10^9,1≤sj≤tj≤n。
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, m, r[N], d[N], s[N], t[N];
bool check(int num){
int sub[N], need[N];
//给sub数组的值全部初始化为0
memset(sub, 0, sizeof(sub));
for(int i = 1; i <= num; i++){
//数组的差分求值,防止累加到重复值
sub[s[i]] += d[i];
sub[t[i] + 1] -= d[i];
}
for(int i = 1; i <= n; i++){
//前缀和求出每一天至少需要多少个房间
need[i] = need[i - 1] + sub[i];
//每一天需要的房间和出租房间比较
if(need[i] > r[i]){//不满足出租要求
return true;
}
}
return false;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> r[i];
}
for(int i = 1; i <= m; i++){
cin >> d[i] >> s[i] >> t[i];
}
int left = 1;
int right = m;
if(!check(m)){//当全部订单均满足
cout << 0;
return 0;
}
int mid, ans;
while(left <= right){
mid = left + (right - left) / 2;
//当订单未满足时,查找第一天未满足的订单
if(check(mid)){
right = mid - 1;
ans = mid;
}else{//订单满足
left = mid + 1;
}
}
cout << "-1" << endl;
cout << ans;
return 0;
}
二、黑手党
**题目:**有n个人在玩游戏"黑手党”,这个游戏规则是每局必须有一个主持,(n -1)名选手。其中第i个人表示想玩ai局游戏且不当主持,请求出满足每人要求的最少的局数。
/**
输入格式:第一行为人数n ;第二行为数列a 。
输出格式:一行一个整数即为答案。
样例1 输入:3
3 2 2
输出:4
备注
其中:3<=n≤ 1e5,1 ≤ai≤ 1e9
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
ll a[N], n, l, r, mid, ans, sum;
bool check(ll num){//满足每个人要求的最少局数返回true
return num * (n - 1) >= sum;
}
int main(){
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
l = max(l, a[i]);//满足所有人要求的最少场数
sum += a[i];//满足所有人要求的最多场数
}
r = sum;
while(l <= r){
mid = l + (r - l) / 2;
//所有选手的平均场所大于等于最大场数时
if(check(mid)){//此时局数多了
r = mid - 1;
ans = mid;
}else{//所有选手的平均场所小于等于最大场数时,此时局数少了
l = mid + 1;
}
}
cout << ans;
return 0;
}
三、合数分解
**题目:**给你一个正整数n,求最多能分成几个合数。若n为合数,它自身算一个合数。无解输出-1 。
/**
输入格式:第一行一个正整数T;接下来T行每行表示一个测试数据。
输出格式:每一行输出一个答案。
样例1 输入:1
10
输出:2
备注
其中:T≤1e5,1≤n ≤1e9
*/
#include<bits/stdc++.h>
using namespace std;
int t, n;
int main(){
cin >> t;
while(t--){
cin >> n;
if(n == 1 || n == 2 || n == 3 || n == 5 || n == 7 || n == 11){
cout << "-1" << endl;//不能拆成合数要做特殊判断
//可以被最小的合数4取余为0,4 -> 4 8 -> 4+4;取余为2,6 -> 4+2 10 -> 4 + 6
}else if(n % 4 == 0 || n % 4 == 2){
cout << n / 4 << endl;//拆分的合数数量
//可以被最小的合数4取余为1,9 -> 4+4+1=4+5、13 -> 4+4+4+1=4+4+5
}else if(n % 4 == 1 || n % 4 == 3){//取余为15 -> 4+4+4+3=4+4+7
cout << n / 4 - 1 << endl;//拆分的合数数量
}
}
return 0;
}
四、屠龙勇者
**题目:**很久很久以前,巨龙突然出现,带来灾难带走了公主又消失不见。后来,一名叫做小码哥的勇者战胜了巨龙,拯救了王国。现在,一头更可怕的多头喷火龙使王国再次面临毁灭。巨龙有n个头,每个头的直径为di,而国王有m个勇士,每个勇士最多只能砍一个头,且能力值为 w的勇士只能砍下直径不超过w的龙头。现在请你计算这些勇士能否消灭这只巨龙。
/**
输入格式:输入共三行,第一行两个正整数 n, m 满足0<n, m ≤1×10^5;第二行n个正整数di;第三行m个正整数wi,满足0<di, wi≤1 × 10^8。
输出格式:输出共一行,若能消灭输出YES,否则输出NO。
样例1 输入:4 5
6 8 4 10
12 3 9 7 4
输出:YES
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, d[N], w[N];
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> d[i];
}
for(int i = 1; i <= m; i++){
cin >> w[i];
}
//核心是间两个数组排序比较即可
sort(d + 1, d + n + 1);
sort(w + 1, w + m + 1);
if(n > m){
cout << "NO";
return 0;
}
for(int i = 1; i <= n; i++){
if(w[i + m - n] < d[i]){//从后等数量比较
cout << "NO";
return 0;
}
}
cout << "YES";
return 0;
}
五、数列分段
**题目:**对于给定的一个长度N的正整数数列Ai,现要将其分成连续的若干段,并且每段和不超过M(可以等于M ),问最少能将其分成多少段使得满足要求。
/**
输入格式:第一行包含两个正整数N,M,表示了数列Ai的长度与每段和的最大值;第二行包含N个空格隔开的正整数Ai,如题目所述。
输出格式:一个正整数,输出最少划分的段数。
样例1 输入:5 6
4 2 4 5 1
输出:3
备注
其中: 1≤N ≤10^5,N<M <10^9,1≤ Ai≤109
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int A[N], n, m, ans, s;
int main(){
cin >> n >> m;
int sum = 0;
for(int i = 1; i <= n; i++){
cin >> A[i];
s = A[1];
//当连续的值相加小于每段的最大值,则组成一个段,形成最少段
if(sum + A[i] <= m){
sum += A[i];
}else{//当连续的值相加大于每段的最大值,重新赋予一段
sum = A[i];
ans++;
}
}
//由于题目没有说是否会有直接大于每段的最大值,做个简单的判断
cout << (s > m ? ans : ans + 1);
return 0;
}
六、小码哥爱数字
**题目:**小码哥很喜欢数字,有一天他找到老师给他出一道有关数字的题目。老师给他一个位数很多的正整数N(不超过250 位),让小码哥去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的非负整数。小码哥觉得老师在刁难他(因为小码哥才一年级),所以他找身为程序员的你编程对给定的N和 k ,寻找一种方案使得剩下的数字组成的新数最小。
/**
输入格式:N(正整数,不超过250位),不必考虑前导0;k(需要删除的数字个数),保证有输出,即k小于n的位数。
输出格式:最后剩下的最小数。
样例1 输入:175438
4
输出:13
*/
#include<bits/stdc++.h>
using namespace std;
string n;
int k, ld0;
int main(){
cin >> n;
cin >> k;
int len = n.length();
while(k--){
//本题解法主要是求剩下的数最小,只需从左往右,将当前数大于后面数删除即可
for(int i = 0; i < len; i++){
if(n[i] > n[i + 1]){//前一个数大于后一个数,则删除当前数
for(int j = i; j <= len; j++){
n[j] = n[j + 1];//将后面的数全部往前挪
}
len--;
break;
}
}
}
//处理前导0
while(ld0 < len - 1 && n[ld0] == '0'){
ld0++;
}
for(int i = ld0; i < len; i++){
cout << n[i];
}
return 0;
}
七、泼墨淋漓
**题目:**小码哥有n幅画,每幅画都有一个编号 ai,编号为非负数且可以相同。他想改变一些画的编号,使得n幅画使用的不同编号数量不超过k ( 1<=k<=n <=200000 ) ,问最少需要改变多少幅画的编号?
/**
输入格式:第一行输入n,k ;第二行输入ai 。
输出格式:输出需要改变编号的画的最少数量。
样例1 输入:5 2
1 1 2 2 5
输出:1
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, k, a[N], b[N], ans;
bool cmp(int a, int b){
return a > b;//降序
}
int main(){
cin >> n >> k;
for(int i = 0; i < n; i++){
cin >> a[i];
//将相同序号的数量累加
b[a[i]] += 1;
}
sort(b, b + N, cmp);
//排完序后从第k个开始,将后面的数字相加
//即是需要改变的编号数量
for(int i = k; i < n; i++){
ans += b[i];
}
cout << ans;
return 0;
}
八、栈的min
**题目:**小码哥又被安排任务了,这次他需要要设计一个堆栈,他除了可以满足正常的栈的操作以外,还要可以输出栈内最小元素值。
o(n)的算法小码哥当然会,小码哥为了给上司一个惊喜决定设计一个o(1)就能输出的程序,自然这个任务就被丢给你了。
-
c(x)
-将元素x插入栈中 -
y()
-移除栈顶元素 -
s()
-得到栈顶元素 -
g_m()
-得到栈中最小元素
/**
输入格式:第一行输入操作个数n(整数);第2行到第n+1行输入一个整数t分别依次代表上述4种操作;当t == 1时,会额外输入一个整数x。
输出格式:当t == 3或t ==4时,输出相应数据,每一行输出一个数据。
样例1 输入:6
1 3
1 4
3
4
2
3
输出:4
3
3
备注
其中: 1<=t<=4;操作命令总数[0,100]。
*/
#include<bits/stdc++.h>
using namespace std;
stack<int> stackValue;//定义常规栈
stack<int> stackMin;//定义栈求最小元素
void push(int x){//将元素x入栈
stackValue.push(x);
if(stackMin.empty() || stackMin.top() >= x){
stackMin.push(x);
}
}
void pop() {//移除栈顶
if(stackMin.top() == stackValue.top()){
stackMin.pop();
}
stackValue.pop();
}
int top(){//得到栈顶元素
return stackValue.top();
}
int getMin(){//得到栈顶元素
return stackMin.top();
}
int main(){
int n;
cin >> n;
while(n--){
int a;
cin >> a;
switch(a){
case 1: //入栈
int x;
cin >> x;
push(x);
break;
case 2: //移除栈顶
pop();
break;
case 3: //出栈,得到栈顶元素
cout << top() << endl;
break;
case 4: //得到栈中的最小元素
cout << getMin() << endl;
break;
}
}
return 0;
}
九、括号家族
**题目:**小码哥在研究只有左括号和右括号组成的序列。给出一个括号序列,求出最长合法子串和它的数量(合法的定义:这个序列中左右括号匹配)。
例如: (()
不合法,)()(
也不合法,但()()
和(())
合法。文章来源:https://www.toymoban.com/news/detail-435664.html
/**
输入格式:输入一行只有左括号和右括号组成的序列(只包含小括号)。
输出格式:输出两个数字:最长子字符串的长度,以及此类子字符串的数量,如果没有这样的子字符串,则输出 0 1 。
样例1 输入:()()))()()(()
输出:4 2
备注
其中:字符串长度小于等于10^6
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
struct NODE{
char c;//括号
int index;//索引
};
bool tag[N];//标记位置
string str;
stack<NODE> s;//初始栈
int main(){
cin >> str;
int len = str.length();
for(int i = 0; i < len; i++){
//如果栈顶元素为( 下一个想要入栈的为),则将(出栈,并给两者标记
if(!s.empty() && s.top().c == '(' && str[i] == ')'){
tag[i] = true;//标记为true,用来后续查看最长的子串
tag[s.top().index] = true;
s.pop();
}else{//不符合则间括号入栈处理
s.push({
str[i],
i
});
}
}
int maxlen = 0, tmp = 0;
//等于len是将进行最后的最大子串比较
for(int i = 0; i <= len; i++){//求最大的子串长度
if(tag[i]){
tmp++;//计算子串的长度
}else{
maxlen = max(maxlen, tmp);//取最大的子串长度
tmp = 0;//每次循环比较结束重置值
}
}
int count = 0;
for(int i = 0; i <= len; i++){//求最大子串的数量
if(tag[i]){
tmp++;//计算子串的长度
}else{
if(tmp == maxlen){
count++;//当子串为最大子串时,数量加1
}
tmp = 0;//每次循环比较结束重置值
}
}
if(maxlen){
cout << maxlen << " " << count;
}else{
cout << "0 1";
}
return 0;
}
记录每一个学习瞬间
文章来源地址https://www.toymoban.com/news/detail-435664.html
到了这里,关于百度松果菁英班--oj赛(第三次)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!