算法竞赛入门【码蹄集进阶塔335题】(MT2076-2100)

算法竞赛入门【码蹄集进阶塔335题】(MT2076-2100)



前言

在这里插入图片描述

为什么突然想学算法了?

> 用较为“官方”的语言讲,是因为算法对计算机科学的所有分支都非常重要。 在绝大多数的计算机科学分支领域中,要想完成任何实质性的工作,理解算法的基础知识并掌握与算法密切相关的数据结构知识是必不可少的。
> 但从实际而言,是因为当下快到了考研和找工作的年纪(ಥ_ಥ),无论走哪一条路,都不免需要一些相对丰富的算法知识,是故,便产生了一个暑假速成算法的计划,可能对于像我这种算法竞赛小白而言,几乎很难,但我仍然还是想尝试一下,毕竟,梦想还是要有的,万一实现了呢?~( ̄▽ ̄~)~

在这里插入图片描述


为什么选择码蹄集作为刷题软件?

码蹄集,是在全国高等学校计算机教学与产业实践资源建设专家委员会(TIPCC) 指导下建设的,其依托全国各大名校计算机系和清华大学出版社等单位的强大资源,旨在为计算机学习爱好者提供全面和权威的计算机习题。
在这里插入图片描述


目录

1. MT2076 小码哥处理订单

(1)题目描述
假期快到了,小码哥在宾馆打暑假工。

小码哥需要处理接下来n天的住房信息,其中第i天宾馆有r;个房间可供租借。共有m份订单,每份订单用三个正整数描述,分别为d;,sj,t,,表示需要从第s;天到第t天住房(包括第sj天和第t天),每天需要出租dj个房间。

宾馆入住是先到先得,如果在分配的过程中遇到一份订单使从第s;天到第t,天中有至少一天剩余的房间数量不足d;个,则需要停止房间的分配,通知当前申请人修改订单。

由于到了假期,宾馆入住人数很多,小码哥需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。他真的太累了,请你编程帮小码哥解决问题


格式

输入格式:
第一行包含两个正整数n,m,表示天数和订单的数量。
第二行包含n个正整数,其中第i个数为r;,表示第i天可用于租借的房间数量,影响到所有需要在这天租借的订单。
接下来有m行,每行包含三个正整数d;,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

(2)参考代码

#include <bits/stdc++.h>
 using namespace std;
 typedef long long int ll;
 typedef unsigned long long int ull;
 #define all(a) a.begin(), a.end()
 #define rall(a) a.rbegin(), a.rend()
 #define fi first
 #define se second
 #define rep(i,s,n) for(int i=s;i<n;i++)
 #define repd(i,s,n) for(int i=s;i>=n;i--)
 const int MOD=1e9+7;
 const int maxN=5e3+1;
 const int INF=2e9;
 const int MB=20;
 const int MAX_LEN=1e6+10;
 ll a[MAX_LEN];
 ll f[MAX_LEN*4],v[MAX_LEN*4];
 inline void bulidtree(int k,int l,int r)
 {
    
    
 v[k]=0;
 if (l==r)
 {
    
    
 f[k]=0;
 return;
 }
 int mid=l+r>>1;
 bulidtree(k+k,l,mid);
 bulidtree(k+k+1,mid+1,r);
 f[k]=f[k+k]+f[k+k+1];
 }
 inline void insert(int k,int l,int r,int x,int y,int z)
 {
    
    
 if (l==x && r==y)
 {
    
    
 v[k]+=z;
 return;
 }
 f[k]+=(y-x+1)*z;
 int mid=l+r>>1;
 if (y<=mid)
 insert(k+k,l,mid,x,y,z);
 else
 if (x>mid)
 insert(k+k+1,mid+1,r,x,y,z);
 else
 insert(k+k,l,mid,x,mid,z),
 insert(k+k+1,mid+1,r,mid+1,y,z);
}
 ll query(int k,int l,int r,int x,int y,ll p)
 {
    
    
 p+=v[k];
 if (l==x && r==y)
 {
    
    
 return f[k]+p*(y-x+1);
 }
 int mid=l+r>>1;
 if (y<=mid)
 return query(k+k,l,mid,x,y,p);
 else
 if (x>mid)
 return query(k+k+1,mid+1,r,x,y,p);
 else
 return query(k+k,l,mid,x,mid,p)+query(k+k+1,mid+1,r,mid+1,y,p);

 }
 int z[MAX_LEN],x[MAX_LEN],y[MAX_LEN];
 void solve()
 {
    
    
 int n,m;
 cin>>n>>m;
 for (int i=1;i<=n;i++)
 cin>>a[i];
 for (int i=1;i<=m;i++)
 {
    
    
 cin>>z[i]>>x[i]>>y[i];
 for (int k=x[i];k<=y[i];k++)
 {
    
    
 a[k]-=z[i];
 if (a[k]<0)
 {
    
    
 cout<<-1<<"\n";
 cout<<i<<"\n";
 return;
 }
 }
 }
 cout<<0<<"\n";

 }
 int main()
 {
    
    
 solve();

 return 0;
 }


2. MT2077 黑手党

(1)题目描述
有n个人在玩游戏"黑手党”,这个游戏规则是每局必须有一个主持,(n一1)名选手。其中第i个人表示想玩α;局游戏且不当主持,请求出满足每人要求的最少的局数。

格式

输入格式: 第一行为人数n,第二行为数列α
.
输出格式: 一行一个整数即为答案

样例1

输入:
3
3 2 2
.
输出: 4

备注:

其中:3≤n ≤le5,1 ≤a[i]≤1e9

(2)参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll sum=0;
bool judge(ll mid){
    
    
    if(mid*(n-1)>=sum) return true;
    return false;
}

int main(){
    
    
    ll l=0,r=0;
    cin>>n;
    for(int i=0;i<n;i++){
    
    
        ll a;
        cin>>a;
        l=max(a,l);
        r+=a;
        sum+=a;
    }
    while(l<r){
    
    
        ll mid=(l+r)/2;
        if(judge(mid)) r=mid;
        else l=mid+1;
    }
    cout<<r;
    return 0;
}

3. MT2078 甜品配置

(1)题目描述
小码哥的上司是一个爱吃甜品的人,他给了小码哥v的经费,去购买m个甜品,这些甜品有b;的价格,和 a;的甜度,上司希望甜度越高越好,但是他比较忙,没有时间来确定所有甜品的甜度,只会去看M个甜品的中位数的甜度,于是小码哥决定在买M个甜品,总价格不超过v的情况下,尽可能的让中位数大。

如果m是偶数,那么中位数就是中间两个甜品的甜度的平均值。

格式

输入格式:
第一行三个数v, n, m,分别代表经费,甜品数量以及需要买的甜品数量
接下来n行,每行两个数a,bi,分别代表甜品甜度以及价格n ≤1e5,1 ≤ m≤n, a≤ 1e9,u ≤ 1e9,bi≤v
.
输出格式: 输出一个整数,最大的中位数

样例1

输入:
20 5 3
3 5
5 6
8 7
10 6
15 10
.
输出: 8

备注:

提示: n ≤1e5,1 ≤m ≤n, ai ≤1e9, u ≤ 1e9,bi ≤v

(2)参考代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct SWEET{
    
    
    int a,b;
}sw[N];
int v,n,m,l,r,mid,ans,sum1[N],sum2[N];

bool cmp(SWEET s1,SWEET s2){
    
    return s1.a<s2.a;}
int main(){
    
    
    cin>>v>>n>>m;
    for(int i=1;i<=n;i++) cin>>sw[i].a>>sw[i].b;
    sort(sw+1,sw+n+1,cmp);

    priority_queue<int> q1,q2;
    for(int i=1;i<=n;++i){
    
    
        q1.push(sw[i].b);
        sum1[i] = sum1[i-1] + sw[i].b;
        if(q1.size() > m/2-1+m%2)
            sum1[i] -= q1.top(),q1.pop();
    }
    for(int i=n;i>0;i--){
    
    
        q2.push(sw[i].b);
        sum2[i] = sum2[i+1] +sw[i].b;
        if(q2.size()>m/2) sum2[i] -= q2.top(),q2.pop();
    }

    if(m%2){
    
    
        for(int i=n-m/2;i>=m/2+1;i--)
            if(sum1[i-1]+sum2[i+1]+sw[i].b<=v){
    
    
                cout<<sw[i].a;
                break;
            }
    }else{
    
    
        for(int i=m/2;i<=n-m/2;i++){
    
    
            l=i+1,r=n-m/2+1;
            int tmp=0;
            while(l<=r){
    
    
                mid = l+(r-l)/2;
                if(sum1[i-1]+sum2[mid]+sw[i].b<=v)
                    l = mid+1,tmp=mid;
                else
                    r = mid-2;    
            }
            if(tmp>i) ans = max(ans,sw[i].a+sw[tmp].a);
        }
        cout<<ans/2<<endl;
    }
    return 0;
}





4. MT2079 第k小的距离

(1)题目描述
给定一个整型数组(n个)表示的位置,请返回所有数对中第k小的距离。一对(A,B)的距离表示A和B之间的绝对差值。

格式

输入格式:
第一行输入两个整型n和k ( n ≤10的6次,0<k <n(n -1)/2 )
第二行输入整型数组
.
输出格式: 输出一个整型

样例1

输入:
3 1
1 3 1
.
输出: 0

(2)参考代码

#include<cstdio>
#include <iostream>
#include <algorithm>
 using namespace std;
 typedef long long ll;
 ll a[100006];
 int n,k;

 ll labs(ll x)
 {
    
    
 if(x<0) return -x;
 else return x;
 }

 bool ck(ll dis)
 {
    
    
 int cnt=0;
 for(int i=0;i<n;i++)
 {
    
    
 int l=i;
 int r=n-1;
 while(l<r)
 {
    
    
 int mid = l+r+1>>1;
 if(labs(a[mid]-a[i])<=dis)
 l=mid;
 else r=mid-1;
 }
 //cout<<"cnt"<<cnt<<endl;
 cnt+=l-i;
 }
 //cout<<dis<<" "<<cnt<<endl;
 if(cnt>=k)
 return true;
 else return false;
 }

 int main( )
 {
    
    

 cin>>n>>k;
 for(int i=0;i<n;i++)
 {
    
    
 scanf("%lld",&a[i]);
 }
 sort(a,a+n);
 ll r=a[n-1]-a[0];
 ll l=0;
 while(l<r)//二分答案
 {
    
    
 ll mid = l+r>>1;
 if(ck(mid))//小于等于mid的数对的数量 大于等于k
 r=mid;
 else l=mid+1;
 }
 cout<<l<<endl;
 return 0;
 }


5. MT2080 均分糖果

(1)题目描述
小码哥有n个手下,位置从1到n ,他们坐成一排,每个人有a;个糖果,每个人只能把糖果送给左右两个人,由于坐在1和n位置上的是术士,他们可以通过技艺,相互传递糖果,每人每次传递一个糖果代价为1。数据保证糖果一定可以被均分,不会出现小数情况。

格式

输入格式:
第一行一个正整数n <1e3,表示手下的个数.
接下来n行,每行一个整数ai,表示第i个手下得到的糖果的颗数.
.
输出格式: 求使所有人获得均等糖果的最少代价。

样例1

输入:
4
9
8
17
6
.
输出: 8

备注:

其中: 1≤n ≤1e3,0 ≤ai≤1e5

(2)参考代码

#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define ll long long
const int N = 1000010;
int n;
ll a[N];
int main() {
    
    
    cin >> n;
    ll ave = 0;
    for (int i = 1; i <= n; i++) {
    
    
        cin >> a[i];
        a[i + n] = a[i] ;
        ave += a[i];
    }
    ave = ave / n;
    ll an = 1e9;
    for (int i = 1; i <= n; i++){
    
    
        ll now = 0, ans = 0;
        for (int j = i; j <= n + i - 1; j++){
    
    
            ll t = now + a[j] ;
            ans += abs(t - ave);
            now = t - ave; 
        }
        an = min (an, ans) ;
        //cout << ans <<" " ;
    }
    cout << an ;
    return 0;
}

6. MT2081 持盾

(1)题目描述

在这里插入图片描述

格式

输入格式:
第一行一个正整数n
第二行到第1+n行,每行两个正整数,表示盾卫的质量和力量
.
输出格式: 输出一个使盾卫中最大的风险值最低的排序下,最大的风险值。

样例1

输入:
3
10 3
2 5
3 3
.
输出: 2

备注:

其中:1<N ≤50000,1 ≤ w≤100000,1≤s ≤1000000000

(2)参考代码

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long 
#define N 1000000
struct op{
    
    
    ll w, s, h ;
} s[N] ;
bool cmp (op a, op b){
    
    
    return a.h < b.h ;
}
int main(){
    
    
    ll n ;
    cin  >> n ;
    for (ll i = 1; i <= n ; i++){
    
    
        cin >> s[i].w >> s[i].s ;
        s[i].h = s[i].s  + s[i].w ;
    }
    sort(s+1, s+1+n, cmp) ;
    ll an = 0, min1 = -1e18;
    for (ll i = 1; i <= n; i++){
    
    
        min1 = max(an - s[i].s , min1) ;
        an = an + s[i].w;
    }
    cout << min1;
    return 0;
}

7. MT2082 合数分解

(1)题目描述
给你一个正整数n ,求最多能分成几个合数。若n为合数,它自身算一个合数。无解输出—1。

格式

输入格式: 第一行一个正整数T,接下来T行每行表示一个测试数据
.
输出格式: 每一行输出一个答案

样例1

输入:
1
10
.
输出: 2

备注:

其中:T≤1e5,1<n ≤1e9

(2)参考代码

#include<bits/stdc++.h> 

using namespace std;

int main( )
{
    
    
    int t;
    cin>>t;
    while(t--){
    
    
        int x;
        cin>>x;
        if(x<4) cout<<-1<<"\n";
        else if((x%4&1)==0) cout<<x/4<<"\n";
        else cout<<(x/4-1==0?-1:x/4-1)<<"\n";
    }
    return 0;
}

8. MT2083 屠龙勇士

(1)题目描述

很久很久以前,巨龙突然出现,带来灾难带走了公主又消失不见。后来,一名叫做小码哥的勇者战胜了巨龙,拯救了王国。现在,一头更可怕的多头喷火龙使王国再次面临毁灭。巨龙有n个头,每个头的直径为d;,而国王有 m个勇士,每个勇士最多只能砍一个头,且能力值为 w的勇士只能砍下直径不超过w的龙头。现在请你计算这些勇士能否消灭这只巨龙。

格式

输入格式:
输入共三行,第一行两个正整数n, m满足0<n, m ≤1 x105。第二行n个正整数d,第三行 m个正整数wi,满足0 <d;, wi,≤1 x 108。
.
输出格式: 输出共一行,若能消灭输出YEs ,否则输出No

样例1

输入:
4 5
6 8 4 10
12 3 9 7 4
.
输出: YES

(2)参考代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn], b[maxn];
int main(){
    
    
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i){
    
    
    	cin >> a[i];
    }
    for(int i = 1; i <= m; ++i){
    
    
    	cin >> b[i];
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + m + 1);
    if(n > m){
    
    
    	cout << "NO" << endl;
    	return 0;
    }
    for(int i = 1; i <= n; ++i){
    
    
    	if(b[i + m - n] < a[i]){
    
    
    		cout << "NO" << endl;
    		return 0;
    	}
    }
    cout << "YES" << endl;
}

9. MT2084 检测敌人

(1)题目描述
在一片废墟里埋藏着许多敌人,他们在隐逸状态下,不能被发现,于是小码哥被派遣去放置装置持续地检测敌人,但是这个公园只有一条笔直的马路,小码哥有许多装置可以放置在马路上,它能搜寻出以装置为中心的半径为r以内的圆里敌人,(包括边界),我们使用直角坐标系,定义马路为α轴,马路两边分别为,y的正半区,和gy 的负半区,现在给出每个敌人的具体坐标以及装置的检测范围,请你求出能够使所有敌人都被装置覆盖所需的最小装置数目。

格式

输入格式:
可能存在多组数据。每组数据格式如下:
第一行输入两个整数n和d,分别代表敌人数目和装置检测范围。
接下来n行,每行输入两个整数,分别代表敌人的a,y轴坐标。
同一行数据之间用空格隔开。
全部数据输入完成后,接受到两个0的数据时结束读取。
.
输出格式: 每组数据输出一个整数。每个整数代表所需的最小装置数目,若没有解决方案则所需数目输出—1。

样例1

输入:
8 20
2 6
1 8
12 6
-12 6
-48 3
12 5
12 9
-12 0
.
0 0
.
输出: 2

样例2

输入:
3 2
1 2
-3 1
2 1
.
1 2
0 2
.
4 6
1 2
2 5
1 4
1 3
.
0 0
.
输出: 2

备注:

其中: 1≤n ≤1000,-1e3≤c, gy,d ≤ 1e3

(2)参考代码

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long 
#define N 10000
struct op{
    
    
    double x , y , ma, mi , v, num;
} s[N] ;
bool cmp(op a, op b){
    
    
    if (a.mi == b.mi) return a.ma < b.ma ;
    return a.mi > b.mi ;
}
int main(){
    
    
    while(1)
    {
    
    
    double n ,r, d = 0;
    cin >> n >> r;
    memset(s,0,sizeof(s) );
    if (n == 0 && r == 0) break;
    for (int i = 1; i <= n; i++){
    
    
        cin >> s[i].x >> s[i].y ;
        if (r*r < s[i].y*s[i].y) d = 1;
        else 
        {
    
    
        s[i].mi = -sqrt(r*r - s[i].y*s[i].y) + s[i].x;
        s[i].ma = sqrt(r*r - s[i].y*s[i].y) + s[i].x;
        s[i].v = 0;
        }
    }
    if (d == 1){
    
    
        cout << -1 << endl;
        continue;
    }
    sort( s+1, s+1+(int)n , cmp) ;
    for (int i = 1; i <= n; i++){
    
    
        s[i].num = i;
        
    }
    ll ans = 0;
    for (int i = 1; i <= n; i++){
    
    
        if (s[i].v == 0 ){
    
    
            for (int j = 1; j <= n; j++){
    
    
                if (s[j].mi <= s[i].mi && s[j].ma >= s[i].mi){
    
    
                    s[j].v = 1;
                }
            }
            ans ++ ;
        }
    }
    printf("%ld\n",ans);
    }
    return 0;
}

10. MT2085 小码哥的福利

(1)题目描述
小码哥的手下越来越多,享受的福利待遇却不太一样,小码哥经常用甜品来奖励他的手下,他希望他们吃到的甜品数量可以一起平均增长,小码哥知道现在这些手下的甜品耐受度为a;,手下可以吃掉小于等于他甜品耐受度的甜品(只要一个甜品的甜度小于等于某个手下的甜品耐受度,这个手下就有能力吃掉它),如果某一个手下吃掉了一个甜品,这个手下吃过的甜品数量就会+1;现在小码哥知道甜品的甜度b;和数量c,他希望可以在吃掉所有甜品的情况下(小码哥不喜欢浪费),使这些手下中吃掉的甜品数量最大的人吃掉的数量尽可能的小。如果不能吃掉所有的甜品,输出-1否则输出最小化最大的吃掉的数量

格式

输入格式:
第一行输入一个整数n表示手下的数量
第二行输入n个整数α表示我方每个手下的甜品耐受度
第三行输入一个整数m表示甜品的种类数
第四行输入m个整数b表示这种类的甜品的甜度的大小
第五行输入m个整数c表示这种甜度的甜品的数量
.
输出格式: 输出一个整数

样例1

输入:
3
2 3 5
3
1 3 4
2 9 4
.
输出: 7

备注:

提示:题目保证没有相同甜品耐受度的手下1<n ≤50,1 ≤ a≤10000,1 ≤m≤50,1 ≤ bi≤10000,1 ≤c≤1014

(2)参考代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
ll const N = 1e5 ;
ll n, a[N], m ;
struct op{
    
    
    ll v, num ;
    bool operator < (op const t){
    
    
        return v < t.v ;
    }
}f[N] ;
int main(){
    
    
    cin >> n;
    for (int i = 1; i <= n; i++){
    
    
        cin >> a[i] ;
    }
    cin >> m;
    for (int i = 1; i <= m; i++){
    
    
        cin >> f[i].v ;
    }
    for (int i = 1; i <= m; i++){
    
    
        cin >> f[i].num ;
    }
    sort(f + 1, f + 1 + m) ;
    sort(a + 1, a + 1 + n) ;
    //cout << f[m].v <<" " << a[n] << endl;
    if (f[m].v > a[n]) {
    
    
        cout << -1 ;
        return 0;
    }
    ll now = n, all = 0, ans = 0;
    for (int i = m; i >= 1; i--){
    
    
        all = all + f[i].num ;
        while (f[i].v <= a[now]) {
    
    
            now -- ;
        }
        if (all % (n - now) == 0) {
    
    
            ans = max(ans, all / (n - now)) ;
        }
        else {
    
    
            ans = max(ans, all / (n - now) + 1) ;
        }
    }
    cout << ans ;
    return 0;
}

11. MT2086 货物买卖

(1)题目描述

在一条马路上有着n个商铺,有些商铺出售物品,有些收购物品,这些物品的价值是相同的所有,每一种物品都被大家接受并且可以用来交易。

我们把这条马路看作一个α轴,小码哥从这条马路的起点出发(即原点),每个商铺的坐标是确定的,他在前进过程中会经过所有的商铺,并且在第n个商铺处停下。

我们已知这些商铺出售的货物之和是大于等于收购的货物之和的,即所有的商铺的需求都可以被满足。小码哥与他们交易不需要时间,而每在a轴上行走一步就需要1单位时间。

小码哥在初始时手上没有货物,他不能卖给某个商铺超过他手上货物总量的货物,且是否买卖货物由他自己决定,但他必须满足所有商铺的需求,他想知道他最少需要花费多少时间。

格式

输入格式:
第一行输入一个整数n
第二行输入n个元素p;表示每个商铺的位置
第三行输入n个元素d表示每个商铺的需求
保证p;单调递增, d。的和非负
.
输出格式: 输出一个整数表示最少需要花费的时间

样例1

输入:
5
3 14 15 92 101
-3 2 3 -3 1
.
输出: 143

(2)参考代码

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long 
#define N 10000
struct op{
    
    
    int x, v ;
}s[N] ;
 
int main(){
    
    
 
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++){
    
    
        cin >> s[i].x ;
    }
    for (int i = 1; i <= n; i++){
    
    
        cin >> s[i].v;
    }
    int x = 0, qian = 0, rich = 0 ,ans = 0; 
    for (int i = 1; i <= n; i++){
    
    
        if (s[i].v < 0) {
    
    
            qian = qian + s[i].v ;
            if (qian < 0 && x == 0) x = s[i].x ;
        }
        else {
    
    
            rich = rich + s[i].v ;
        }
        if (rich >= -qian && qian != 0) {
    
    
            ans = ans + (s[i].x - x) * 2 ;
            //cout << ans <<" " ;
            x = 0;
            rich = rich + qian ;
            qian = 0;
        }
    }
    cout << ans + s[n].x;
 
    return 0;
}

12. MT2087 仙水购置

(1)题目描述
小码哥有Ⅳ个瓶子,都是由十分珍贵的材料制作的,所以他一直只有N个,以至于当他需要多于Ⅳ种的仙水时,不得不把某一种仙水倒掉来盛放最新需要的仙水。

现在小码哥需要完成一项工作,需要使用瓶子的仙水,如果瓶子里缺少当前需要的仙水,他就会去购买,初始他的瓶子里没有任何一种仙水

现在给定一个小码哥需要的长度为p 的仙水序列,问小码哥至少需要购买多少次仙水,

如果瓶子里没有小码哥需要的仙水,他不得不倒掉某一种,但不清楚应该倒哪一种,你可以帮小码哥决定倒哪一种,来使他购买仙水的次数最少。

格式

输入格式:
若干组数据
请读取到文件末尾
对于每组数据,第一行三个数,N,m( W用到的仙水种类数,用1到m来表示),p(表示序列长度)
第二行p个数,仙水序列
.
输出格式: 对于每一组数据输出一行,一个数字,表示最少的购买次数。

样例1

输入:
2 3 5
3 1 2 1 2
3 4 5
3 2 1 4 3
.
输出:
3
4

备注:

提示:0<n, m,p ≤50000
一种仙水可以反复使用的,只要在瓶子里,使用次数就无限

(2)参考代码

#include<bits/stdc++.h>
 
using namespace std;
const int N=1e5+10;
int a[N], vis[N], ne[N], last[N];
priority_queue<pair<int,int>>l;
void init(){
    
    
    while(!l.empty()) l.pop();
    memset(vis,0,sizeof(vis));
    memset(ne,0,sizeof(ne));
    memset(last,1000010,sizeof(last));
}
int main()
{
    
       
    int n,m,q;
    while(cin >> n >> m >> q)
    {
    
    
        init();
        for(int i=1;i<=q;i++)
            cin>>a[i];
        for(int i=q;i>=1;i--){
    
    
            ne[i]=last[a[i]];
            last[a[i]]=i;
        }
        int ans=0;
        for(int i=1;i<=q;i++){
    
    
            if(ans<n&&!vis[a[i]]){
    
    
                ans++;
                vis[a[i]]=1;
            }
            else if(ans>=n&&!vis[a[i]]){
    
    
                ans++;
                vis[l.top().second]=0;
                vis[a[i]]=1;
                l.pop();
            }
            l.push({
    
    ne[i],a[i]});
        }
        cout<<ans<<endl;
    }
    return 0;
}

13. MT2088 中暑的竹鼠

(1)题目描述
夏天来了,竹鼠们中暑了,小码哥要挨个"照顾”这些竹鼠,使它们恢复健康。

已知一共有Ⅳ只竹鼠中暑,每个竹鼠需要的照顾时间是T,请问怎么排列这N只竹鼠的照顾次序,可以使N只竹鼠的平均等待时间最短。

格式

输入格式:
第一行为一个整数N。
第二行N个整数,第i个整数Ti表示第i个人的照顾时间。0<N ≤500,T ≤105
.
输出格式: 一个浮点数,表示最小的平均等待时间,输出结果精确到小数点后两位。

样例1

输入:
4
1 2 3 4
.
输出: 2.50

备注:

样例1所示,当照顾顺序为1,2,3,4时,所有竹鼠的等待时间是0+1+3+6= 10,10/4 =2.50

(2)参考代码

#include<bits/stdc++.h> 
using namespace std;
int a[1000];

int main( )
{
    
    
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    double sum=0;
    int t=0;
    for(int i=1;i<n;i++){
    
    
        t+=a[i-1];
        sum+=t;
    }
    printf("%.2lf",sum/n);
    return 0;
}

14. MT2089 逃课(不是)

(1)题目描述
哪怕是小码哥,也存在想要逃课的时候(不知道被谁带坏了)。

现在,他决定逃掉一些课,每一节课都有它的种类和疲劳度,只要上了某节课,小码哥就会获得一些疲劳度。但由于还存在理智,小码哥知道不能逃两节种类相同的课(会被老师发现)。现在请你帮小码哥设计逃课计划,使得他的疲劳度最小。

PS:小码哥才不会逃课!逃课的都是坏孩子!逃课仅仅是想法而已嘿嘿嘿,新年还是要学习的!

格式

输入格式:
第一行一个整数n,表示课的数目。接下来n行每行两个数ai,w;,表示这节课的种类和疲劳度。
.
输出格式: —行一个整数表示最少的疲劳度。

样例1

输入:
3
1 2
1 3
2 3
.
输出: 2

(2)参考代码

#include<bits/stdc++.h> 
 
using namespace std;
struct courses {
    
    
 int type;
 int tired;
 };
 bool mycomp(courses i, courses j) {
    
    
 if(i.type==j.type)
 return (i.tired < j.tired);
 return (i.type < j.type);
 }
 int main()
 {
    
    
 vector<courses> cousList;
 courses temp;
 int length = 0;
 cin >> length;
 while (length--)
 {
    
    
 cin >> temp.type >> temp.tired;
 cousList.push_back(temp);
 }
 sort(cousList.begin(), cousList.end(), mycomp);
 unsigned long int count = 0;
 unsigned int key = cousList[0].type;
 bool changed = true;
 for (int i = 1; i < cousList.size(); i++)
 {
    
    
 if (cousList[i].type == key)
 {
    
    
 changed = false;
 count += cousList[i-1].tired;
 }
 else
 {
    
    
 key = cousList[i].type;
 changed = true;
 }
 }
 cout << count << endl;
 return 0;
 }



15. MT2090 竹鼠发瓜子

(1)题目描述
今天小码哥兄弟俩打算给竹鼠们发瓜子吃。竹鼠们排成一列纵队,兄弟俩会根据竹鼠的体重来评定发瓜子的数量。

其中第i个竹鼠的体重是a,发瓜子时需要满足以下要求:
1.相邻竹鼠中体重高的竹鼠的瓜子必须更多,若它们体重相等,则它们分到的瓜子数量必须相等。
2.每只竹鼠至少有一个瓜子。
3.因为经费有限,在满足条件1和2的前提下,发出尽可能少的瓜子。

格式

输入格式:
第一行是一个整数n,表示竹鼠的个数。
第二行有n个整数,表示竹鼠们的体重。
.
输出格式: 最少要准备的瓜子数量。

样例1

输入:
5
3 4 5 4 3
.
输出: 9

(2)参考代码


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int ai[N],ao[N];
ll res[N];
int main()
{
    
    
  int n,min_pt,sum=0;
   cin >> n;
  for (long i = 0; i < n; i++)
 {
    
    
 cin >> ai[i];
 if (ai[i] < ai[min_pt])
 min_pt = i;
 }
 ao[min_pt] = 1;
 for (long i = min_pt; i < n - 1; i++)
 if (ai[i] < ai[i + 1]) ao[i + 1] = ao[i] + 1;
 else if (ai[i] > ai[i + 1])
 {
    
    
 ao[i + 1] = 1;
 if (ao[i] <= 1)
 {
    
    
 long nt = i;
 do {
    
    
 ao[nt]++;
 nt--;
 if (((ao[nt] > ao[nt + 1]) && (ai[nt] > ai[nt + 1])) ||((ao[nt] == ao[nt + 1]) && (ai[nt] == ai[nt + 1])))
 break;
 } while (ai[nt] >= ai[nt + 1]);
 }
 }
 else ao[i + 1] = ao[i];
 for (long i = min_pt; i > 0; i--)
 if (ai[i] < ai[i - 1]) ao[i - 1] = ao[i] + 1;
 else if (ai[i] > ai[i - 1])
 {
    
    
 ao[i - 1] = 1;
if (ao[i] <= 1) {
    
    
 long nt = i;
 do{
    
    
 ao[nt]++;
 nt++;
 if (((ao[nt] > ao[nt - 1]) && (ai[nt] > ai[nt - 1])) ||((ao[nt] == ao[nt - 1]) && (ai[nt] == ai[nt - 1])))
 break;
 } while (ai[nt] >= ai[nt - 1]);
 }
 }
 else ao[i - 1] = ao[i];
 for (long i = 0; i < n; i++) sum += ao[i];
 cout << sum << endl;
}



16. MT2091 竹鼠发瓜子(二)

(1)题目描述

小码哥一口气买了一包有m颗瓜子的qiaqia瓜子,现在要把这些瓜子分给n只竹鼠。

每只竹鼠都有一个瓜子的期望值,如果没有达到竹鼠的期望值,竹鼠就会生气,竹鼠生气的程度等于它少得到瓜子数的平方。

小码哥要合理分配糖果,使竹鼠们生气的程度之和最小。

格式

输入格式:
第一行两个整数m和n。
第二行n个整数,表示竹鼠的期望值。
.
输出格式: 输出一个整数,竹鼠们的最小生气总数。

样例1

输入:
10 4
4 5 2 3
.
输出: 4

(2)参考代码

import time
from typing import List, Tuple
from collections import deque, Counter
from queue import PriorityQueue
import math
from functools import lru_cache
import random
import copy
import sys

sys.setrecursionlimit(99999999)


def main():
    a, b = map(int, input().split())
    arr = list(map(int, input().split()))
    arr.sort()

    tot = sum(arr)
    tot -= a
    cnt = b
    ans = []
    for v in arr:
        avg = tot // cnt
        x = tot % cnt
        if v <= avg:
            ans.append(v)
            tot -= v
        else:
            if x > 0:
                ans.append(avg + 1)
                tot -= (avg + 1)
            else:
                ans.append(avg)
                tot -= avg
        cnt -= 1

    val = 0
    for v in ans:
        val += v ** 2

    print(val)


if __name__ == '__main__':
    main();

17. MT2092 水温调节

(1)题目描述
小码哥家里的浴缸里有一个冷水龙头和一个热水龙头,流出的水温分别是t和tz;它们的流速最大是每秒a和a2个单位,并且可以调节到О至最大流速间的任意一个整数速度。假如两个龙头的流速分别是y和y2( 0≤g1,32 ≤10),那么最终的水温就是

在这里插入图片描述

现在,你要安排两个水龙头的流速,满足:
1.最终水温不低于t0 ;
2.在满足上一条的前提下,水温尽可能接近t0;
3.在满足上一条的前提下,总流速尽可能大。


格式

输入格式: 一行5个整数t1, t2,C1, 02, to ; 1<t1≤to≤t2≤10R; 1≤Z1 , 2 ≤106
.
输出格式: 输出一行两个数表示y1和 y2

样例1

输入: 10 70 100 100 25
.
输出: 99 33

备注:

一定要仔细注意数据范围。

(2)参考代码

#include<bits/stdc++.h>
using namespace std;
int t1,t2,x1,x2,t0;
double best=0x3f3f3f3f,t;
pair<int,int> ans;
int main()
{
    
    
	cin>>t1>>t2>>x1>>x2>>t0;
	double y1=x1,y2=x2;
	while(y1>=0&&y2>=0)//坑点一:这里是“>=”而不是“>”
	{
    
    
		t=double(t1*y1+t2*y2)/(y1+y2);//坑点二:别忘了转double
		if(t<t0) {
    
    y1--; continue;}//先考虑温度高的情况
		if(t-t0<best) best=t-t0,ans.first=y1,ans.second=y2;
		//坑点三:这里如果写成if(t<best)best=t的话会在精度上出问题
		y2--;//最后考虑温度低的情况
	}
	cout<<ans.first<<' '<<ans.second<<endl;
	return 0;
}


18. MT2093 活动安排

(1)题目描述
小码哥又被安排去处理公司的大厅了,公司只有一个大厅,但有许多的活动需要召开,所以需要提前预约,该公司有n 个部门,每个部门会举办一个活动。每个部门会向小码哥上报他们预期使用大厅的时间区间 (a,b)(开区间),小码哥会根据这些情报做安排,一个时间只能有一个活动在召开,活动一旦开始必须结束才能进行下一个活动。

小码哥想要尽可能多的满足活动的召开,于是请你来安排活动。


格式

输入格式:
第一行一个整数n,代表部门的个数。
接下来的n行,每行两个整数a,b,代表时间区间。
.
输出格式: 输出一个整数代表能够召开的最大活动个数。

样例1:

输入
4
1 3
4 6
2 5
1 7
.
输出:2

(2)参考代码

#include<bits/stdc++.h> 

using namespace std;

typedef pair<int,int> PII;
PII t[500010];

bool cmp(PII a,PII b){
    
    
    return a.second<b.second;
}


int main( )
{
    
    
    int n;
    cin >> n;
    int l,r;
    for(int i=1;i<=n;i++){
    
    
        scanf("%d%d",&l,&r);

        t[i] = make_pair(l,r);
    }
    sort(t+1,t+1+n,cmp);

    r = t[1].second;
    int ans = 1;
    for(int i=2;i<=n;i++){
    
    
        if(r<=t[i].first){
    
    
            r = t[i].second;
            ans++;
        }
    }
    cout << ans <<endl;
    
    return 0;
}

19. MT2094 甜品供应

(1)题目描述
在这里插入图片描述


格式

输入格式:
第1行:两个空格分隔的整数:C和L
第2…C+1行:每行用两个整数描述手下i 的甜度要求:l和Ti
第C+2.….C+L+1行:每行两个整数描述某一种甜品的甜度和个数:u;和numi
.
输出格式: 带有整数的单行,表示可以使最多的手下吃到他们喜欢的甜品的人数。

样例1

输入:
3 2
3 10
2 5
1 5
6 2
4 1
.
输出: 2

(2)参考代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+7;

struct PEOPLE{
    
    
    int l,r;
    bool operator<(const PEOPLE &a) const{
    
    
        if(l==a.l) return r<a.r;
        return l<a.l;
    }
}people[N];
struct SWEET{
    
    
    int v,num;
    bool operator>(const SWEET &a) const{
    
    return v>a.v;}
};
int C,L,cnt[N],ans;
priority_queue<SWEET, vector<SWEET>, greater<SWEET>> q;


int main() {
    
    
    cin>>C>>L;
    for(int i=1;i<=C;i++)
        cin>>people[i].l>>people[i].r;
    sort(people+1,people+1+C);
    for(int i=1;i<=L;i++){
    
    
        SWEET t;
        cin>>t.v>>t.num;
        cnt[t.v] += t.num;
        q.push(t);
    }
    for(int i=1;i<=C;i++){
    
    
        while((!q.empty())&&q.top().v<people[i].l)
            q.pop();
        if(!q.empty() && q.top().v <= people[i].r){
    
    
            ans++;
            cnt[q.top().v]--;
            if(cnt[q.top().v]==0)
                q.pop();
        }
    }
    cout<<ans;
    return 0;
}

20. MT2095 斐波那契数列的组合

(1)题目描述
给定一个正整数n,请写一个函数 MinFibonacciNumbers,返回和为n的斐波那契数字的最少数目。

斐波那契数列:
F1=1
F2=1
Fn= Fn-1+Fn-2,n > 2
保证一定存在解。

格式

输入格式: 第一行输入正整数n
.
输出格式: 输出满足要求的数字的最少数目。

样例1

输入: 19
.
输出: 3

(2)参考代码


arr = [1,1]
while arr[-1] < 10**9:
    arr.append(arr[-1]+arr[-2])


def main():
    #code here
    tot = int(input())
    cnt = 0
    for v in arr[::-1]:
        while v <= tot:
            tot -= v
            cnt += 1
        if tot == 0:
            break
    print(cnt)

if __name__ == '__main__':
    main();

21. MT2096 数列分段

(1)题目描述
对于给定的一个长度为Ⅳ的正整数数列Ai,现要将其分成连续的若干段,并且每段和不超过M(可以等于M ),问最少能将其分成多少段使得满足要求。

格式

输入格式:
第1行包含两个正整数N, M ,表示了数列A的长度与每段和的最大值,第2行包含NⅣ个空格隔开的正整数A,如题目所述。
.
输出格式: 一个正整数,输出最少划分的段数。

样例1

输入:
5 6
4 2 4 5 1
.
输出: 3

(2)参考代码


def main():
    #code here
    N,M=map(int, input () .split ())
    num=list(map(int, input () .split ()))
    s=0
    res=1
    for i in range(N):
        if s+num[i]<=M:
            s+=num[i]
        else:
            res+=1 
            s=num[i]
    print(res)
    pass


if __name__ == '__main__':
    main();

22. MT2097 小码哥爱数字

(1)题目描述
小码哥很喜欢数字,于是一天他找到老师给他出一道有关数字的题目。老师给他一个位数很多的正整数N(不超过250位),让小码哥去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的非负整数。小码哥觉得老师在刁难他(因为小码哥才一年级),所以他找身为程序员的你编程对给定的N和k,寻找—种方案使得剩下的数字组成的新数最小。

格式

输入格式:
n(高精度的正整数)。不必考虑前导0。
k(需要删除的数字个数)。保证有输出,,即k小于n的位数。
.
输出格式: 最后剩下的最小数。

样例1

输入:
175438
4
.
输出: 13

(2)参考代码

from collections import deque,Counter
from queue import PriorityQueue

def main():
    #code here
    s = str(int(input()))
    k = int(input())
    n = len(s)

    bits = n-k;
    que = PriorityQueue()
    for i in range(n-bits):
        que.put((s[i],i))

    cur_pos = -1
    ans = []
    all_zero = True
    pos = None
    for i in range(n-bits,n):
        que.put((s[i],i))

        while que.queue[0][1] <= cur_pos:
            que.get()

        v,idx = que.get()
        ans.append(v)
        if v!= '0':
            if all_zero:
                pos = len(ans)-1
                all_zero = False
        
        cur_pos = idx
    
    if all_zero:
        print(0)
        return 
    
    print(''.join(ans[pos:]))

if __name__ == '__main__':
    main();


23. MT2098 泼墨淋漓

(1)题目描述
小码哥有n幅画,每幅画都有一个编号ai,编号为非负数且可以相同。他想改变一些画的编号,使得n幅画使用的不同编号数量不超过k,问最少需要改变多少幅画的编号?

数据范围1≤k≤n ≤200000。

格式

输入格式: 第一行输入n, k,第二行输入i 。
.
输出格式: 输出需要改变编号的画的最少数量。

样例1

输入:
5 2
1 1 2 2 5
.
输出: 1

(2)参考代码

#include<bits/stdc++.h> 

using namespace std;

int n,k;
map<int,int> cnt;
vector<int> a;
int main( )
{
    
    
    cin>>n>>k;
for (int i=1,x;i<=n;++i){
    
    
cin>>x;
if(cnt.count (x))++cnt[x];
else cnt [x]=1;
}
for (map<int,int>::iterator it=cnt.begin();it!=cnt.end();++it)a.emplace_back(it->second);
sort (a.begin(),a.end ());
if(a.size()<=k){
    
    cout<<0<<endl;return 0;} 
int sum(0);
for (int i=1;i<=k;++i)
sum+=a[a.size()-i];
cout<<n-sum<<endl;
    return 0;
}

24. MT2099 很重的枪

(1)题目描述
刻俄柏在打怪,她的面前有n个怪,第 i个怪的血量为ai。对于一个怪物,她有两种攻击方式:

1.使用ai次普通攻击消灭该怪物
⒉.施放一次技能消灭该怪物

刻俄柏最多只能使用k次技能,她想知道最少使用多少次普通攻击消灭所有怪物。

格式

输入格式:
第一行输入n,k,第二行输入ai。数据范围0≤ai,k ≤1091≤n ≤2×105。。
.
输出格式: 输出使用普通攻击的最少次数。

样例1

输入:
3 1
4 1 5
.
输出: 5

(2)参考代码

#include<bits/stdc++.h> 

using namespace std;
int a[200010];
int main( )
{
    
    
    int i,j,k,m,n;
    long long sum=0;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;i++){
    
    
        scanf("%d",&a[i]);
    }
    sort(a+1,a+n+1);
    for(i=1;i<=n-k;i++){
    
    
        sum+=a[i];
    }
    printf("%lld\n",sum);
    return 0;
}

25. MT2100 小船过河

(1)题目描述

n个人想要过河,但现在只有一条小船(有船夫)。小船每次最多载两人过河(不考虑船夫),且有最大承载重量t。请计算小船最少要来回几次。

格式

输入格式:
第一行输入2个整数n和t(0<n ≤105,0<t<232 )
第二行输入n个整数代表每个人的体重(范围:[1,232-1],均小于t)
.
输出格式: 输出一个整数

样例1

输入:
4 3
3 2 2 1
.
输出: 3

(2)参考代码

 #include <bits/stdc++.h>

 using namespace std;

 int main() {
    
    
 cin.tie(NULL)->ios_base::sync_with_stdio(false);
 int n, m;
 cin >> n >> m;
 vector<int> v(n);

 for (auto &x : v)
 cin >> x;

 multiset<int> s;

 for (auto x : v)
 s.insert(x);

 int ans = 0;

 while (!s.empty()) {
    
    
 auto x = *s.rbegin();
 s.erase(s.find(x));

 if (!s.empty() && s.upper_bound(m - x) != s.begin())
 s.erase(prev(s.upper_bound(m - x)));

 ++ans;
 }
 cout << ans << endl;

 return 0;
 }


结语

感谢大家一直以来的不断支持与鼓励,码题集题库中的进阶塔350题正在逐步更新,之后会逐步跟进星耀,王者的题,尽请期待!!!
同时,也希望这些题能帮助到大家,一起进步,祝愿每一个算法道路上的“苦行僧”们,都能够历经磨难,终成正果,既然选择了这条路,走到了这里,中途放弃,岂不是太过可惜?

另附中国计算机学会的杰出会员、常务理事轩哥博士的B站视频讲解链接https://space.bilibili.com/518554541/?spm_id_from=333.999.0.0,供大家更好的进行学习与刷题~( ̄▽ ̄~)~

愿你的结局,配得上你一路的颠沛流离。

猜你喜欢

转载自blog.csdn.net/m0_54754302/article/details/128283245