月赛补题

题目1内卷

期末有n个同学写论文,第i个人写论文的字数在 [ Li , Ri ] 之间,定义wi为某个同学写的字数。
所以Li≤wi≤Ri
而成绩的得分是非常有趣的,第i个同学gi的论文得分为n-Ki
Ki是比当前这个人的论文字数多的人数
每个人都想写尽可能多的字,因为每位同学都想尽可能得到更高的得分。
所以很容易想到让wi=Ri即可。
但是zks发现了有一个有趣的现象
假设对于每位同学来说,∀i∈[1,n] Li=1000,Ri=10000. 那么在最积极情况下,每位同学都写10000字,即wi=10000.
所以每位同学的得分都为n-0(ki=0,因为没有被任何同学超过)。但是如果每位同学都写1000字,每个人的得分仍然为n-0.
这种现象被称之为内卷
感受到内卷的威力了嘛?!
现在让你尽可能降低1~n位同学所有字数总和的情况下,即min{w1+w2+…+wn} 的同时保证每位同学不能低于在尽自己最大努力时所能得到的分数
你能帮帮zks解决这个问题吗?
输入
第一行有一个正整数n
接下来有n行,第i行有两个正整数Li,Ri
1≤n≤1e5
1≤Li≤Ri≤1e9
输出

输出最小的 w1+w2+…+wn的值

样例输入
3
1 10000
1 10000
1 10000
样例输出
3

大意是说找到一个数,是所有学生能拿到他付出最小的努力能拿到的最高名次,且保证在这条件下所有人的字数最少。

下面是代码

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

#define MAX 0x3f3f3f3f
typedef long long ll;
const int M = 1e5 + 10;
#define bug(a) cout<<endl<<"*"<<a<<endl;
struct node
{
	ll l, h;
}arr[M];
bool cmp(node a,node b) {//先将最多努力的排一下,要是一样的最大
	if (a.h == b.h) {//努力,那么可以将那群人最少的努力最大的放前面
		return a.l > b.l;//要是需要加快编译速度,可以用这个来跳过
	}					//毕竟这群人最大的都比那个小嘛
	else return a.h < b.h;
}
int main()
{
	ll n, i, j,ans=0;
	cin >> n;
	for (i = 1; i <= n; i++) {
		cin >> arr[i].l >> arr[i].h;

	}
	sort(arr, arr + n+1, cmp);//将序排好
	int min = 0;
	for (i = 1; i <= n; i++) {
		if (arr[i].l <= min) {//最大努力的那个值比他大的那个人要是
			ans += min;//最小努力比他的最小努力还小可以定为一级
		}//这就相当于拿最少努力拿最大名词且字数和最小
		else {
			min = arr[i].l;//如果最小的比你那个等级的要大,那么就
			ans += min;//换到下一等级去了,以此类推。
		}
	}
	cout << ans << endl;
}

我这属于代码简化版,好理解的和计算效率快的,还请参考要代码点这

发个牢骚

一开始题目看错了,(同时保证每位同学不能低于在尽自己最大努力时所能得到的分数)这句话让我百思不得其解,没明白这意思,后面看了我打算打冲省一的浩哥的代码,才发现可以往前挪一个等级,我之前思路一直都是往后挪一个等级(因为满足最小努力最高名次嘛),所以一直不明白这最小字数又怎么满足,看样子多读书还是好的啊,尤其是语文

题目2俊哥爬山

你看我还有机会吗

刘俊学长在一个深山老林里冒险,这里到处都是山,第i座山的高度记为hi
当hi-1<hi且hi+1<hi时,刘俊学长将会讨厌这座山,也就是第i座山。因为它需要消耗更多的体力翻越。
然而zks是一位魔法师,他可以使一座山凭空消失,而它旁边的两座山会神奇般的连接起来。
例如有7座山,高度为 1 9 1 9 8 1 0 当对第三座山施加魔法时,剩下的六座山为1 9 9 8 1 0
zks希望在释放魔法后,刘俊学长讨厌的山会尽可能的变少。那么最少会有多少座山令刘俊学长讨厌呢? 魔法只能释放一次。

输入

有多组样例测试
第一行为一个整数n,代表有n座山
第二行包含n个正整数 h1,h2,…,hn,代表山的高度
1≤n≤1e5, 0≤hi≤1e9

输出

在释放魔法后,刘俊最少会讨厌的山的数量
样例输入
6
1 1 4 5 1 4
7
1 9 1 9 8 1 0
10
2 1 4 7 4 8 3 6 4 7
样例输出
1
0
2
其实这道题超级简单,题目一直看错,该戴眼镜了……
就是消除一座山,使剩下的山最少,上面的数字是离地高度要大于两边的高度才是一座山,而不是一个高度一座山(不要向我一样蠢)
思路是给他把所有山的坐标找出来保存在一个数组里面,再起一个for循环去判断,有个细节:山一样高的时候输出应该是0,而不是1。
下面是代码

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

#define MAX 0x3f3f3f3f
typedef long long ll;
#define bug(a) cout<<endl<<"*"<<a<<endl;

const int m = 1e5 + 10;
int arr[m],brr[m];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie();
    cout.tie();
    int n, i, j;
    while (cin >> n) {
        memset(arr, 0, sizeof(arr));//记得清零
        memset(brr, 0, sizeof(brr));
        int k = 0;//记山有多少座
        for (i = 1; i <= n; i++) 
            cin >> arr[i];
        for (i = 1; i <= n; i++) {
            if (arr[i] > arr[i - 1] &&arr[i-1]&&arr[i+1]&& arr[i] > arr[i + 1]) {
                brr[++k] = i;
            }
        }
        int ans1 = k,ans=MAX;//ans1是给介值,用来得到ans的最小的,因为可能是k-1也有可能是k-2
        if (k == 0)cout << "0" << endl;//山为0时输出为0
        else {
            for (i = 1; i <= k; i++) {  
                if (arr[brr[i - 1]]&& brr[i]- brr[i - 1] == 2) {//如果两座山中间那个消掉可以令两座山连在一起且高度相同,相当于消去两座山
                    if (arr[brr[i]] == arr[brr[i - 1]])ans = min(ans1-2,ans);
                }
                else if (arr[brr[i] - 2] && arr[brr[i] + 2] && arr[brr[i] - 1] && arr[brr[i] + 1] && ((arr[brr[i] - 1] > arr[brr[i] + 1] && arr[brr[i] - 1] > arr[brr[i] - 2]) || (arr[brr[i] + 1] > arr[brr[i] - 1] && arr[brr[i] + 1] > arr[brr[i] + 2]))) {
                //如果消去一座山以后会生成一座新的山,那么相当于没变
                    ans = min(ans, ans1);
                }
                else { ans = min(ans, ans1 - 1); }//其他情况就是可以少一座山
            }
            cout << ans << endl;
        }
    }
    return 0;
}

题目3最小互质数

我们定义两个数的互质数当且仅当gcd(a, b) = 1。
现在L手里有n个数,分别为a1,a2,a3 ……an-1,an 。
问,没有在这n个数中出现过并且与这n个数都互质的最小的数是多少。
LL觉得这个问题太简单了,于是她把这个问题交给你来解决。

输入
第一行一个数n (1 ≤ n, ai ≤ 10^5)
接下来n行,每行一个数,分别代表a1,a2,a3 ……an-1,an 。
输出
输出一行代表答案

样例输入
5
1
2
3
4
5

样例输出
7

提示

没有在这n个数中出现的数有:6,7,……
6与2, 3, 4不互质,最小的与这n个数互质的数就是7了。

其实把所有质数取出来就行只是这道题还有个1也要算进来,特殊一点
这里给一个取出质数的代码

void prime()
{
    int tot=1;
    memset(v,true,sizeof(v));v[1]=false;
    for(int i=2;i<N;++i)//n为素数的最大界限,自己定义
    {
        if(v[i]) ans[tot++]=i;//ans数组存所有素数
         for(int j=1;(j<tot)&&(i*ans[j]<N);++j)
         {
             v[i*ans[j]]=false;
             if(i%ans[j]==0) break;
         }
    }
}

接下来就是这道题的代码呈上

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

#define MAX 0x3f3f3f3f
typedef long long ll;
#define bug(a) cout<<endl<<"*"<<a<<endl;

const int m = 1e5 + 10;
int arr[m],brr[m];
bool crr[m];
map<int, bool>p;
void juge(int &cnt)
{
    int i, j;
    cnt = 1;
    memset(crr, true, sizeof(crr));
    //crr[1] = false;
    brr[cnt++] = 1;//这里是将1放进这个存素数的数组里,所以上面被注释了
    for (i = 2; i < m; i++) {
        if (crr[i])brr[cnt++] = i;
        for (j = 2; (j < cnt) && (brr[j] * i < m); j++) {
            crr[i * brr[j]] = false;
            if (i % brr[j] == 0)break;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie();
    cout.tie();
    int n, i, j,cnt;
    cin >> n;
    for (i = 1; i <= n; i++) {
        cin >> arr[i];
        p[arr[i]] = true;//map函数初始为false,所以出现的数全部定为true就行
    }
    juge(cnt);//进行素数的收集
    for (i = 1; i <cnt; i++) {
        int flag = 1;
        if (p[brr[i]] == true)continue;//如果有一样的就跳过
        for (j = 1; j <= n; j++) {
            if (arr[j] %brr[i]==0&&i!=1) {//输入的数刚好是此素数的倍数也不行
                flag = 0;//因为他们俩最大公约数不是1,例如3是素数,9和3便不满足条件了
                break;
            }
        }
        if (flag)break;
    }
    cout << brr[i] << endl;
    return 0;
}

题目4放置游戏

zks正在和mqj玩一个数字游戏,游戏规则如下
zks在水平数轴上放置了n个正整数,第i个数为ai
mqj放置了m个正整数,第j个数为bj
现在由瑶姐在水平数轴上任意位置放置一个实数c
如果存在一个ai ( 1≤i≤n) ,对所有bj (1≤j≤m)来说,都满足| c-ai |<| c-bj |时,那么zks将获得一分。
而瑶姐希望zks分数尽可能高,所以实数c的放置位置就至关重要。
如果zks得分为0,输出Impossible
请你帮瑶姐计算zks最高得分为多少

输入
有多组测试数据
第一行为两个正整数n,m (1≤n,m≤1e5)
第二行为n个正整数a1,a2…an
第三行为m个正整数b1,b2…bm
1≤ai,bi≤1e9
输出
输出zks最高的得分,如果为无法得分,则输出Impossible
样例输入
2 2
2 3
1 4
6 5
2 5 3 7 1 7
3 4 3 1 10
1 1
7
7
样例输出
2
3
Impossible
提示
第一个例子:当c=2.5时,zks将得2分
第二个例子: 当c=7时,zks将得3分
第三个例子:无论瑶姐把实数c放在哪 ,zks都无法得到分。
思路:(将公式转成点到每个点的距离就好理解了)
将mqj的数与0和无限大一起分成m+1个区间(前提是没有重复的,要是有重复的可以用unique函数弄掉unique)然后再把zks的数放进去,然后取得zks的数能放进区间最多的个数就行。
举个例子(已经排好序了)
zks a[1],a[2],a[3]
mqj b[1],b[2],b[3]
将mqj的三个数和0和无穷大一起排,得到3+1个区间因为有3+1个数嘛,
然后假设zks三个数都比mqj的小,那么取一个比a[1]还小的数k,mqj的所有数便都比zks的数离k远。
如果zks的数有两个在a[1]和a[2]之间,取a[1]和a[2]中间那个数h,那么张克胜那两个数将会比mqj所有的数都里h近,并且因为是两个,比另外一个多,所以最多是2.
下面是代码

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

#define MAX 0x3f3f3f3f
typedef long long ll;
#define bug(a) cout<<endl<<"*"<<a<<endl;

const int M = 1e5 + 10;
ll arr[M], brr[M];
map<ll,ll>node;//标记点,标记zks的数是否和mqj的数相同
queue<ll >p;//队列
int main()
{
	ll n, m, i, j;
	while (cin >> n>>m)
	{
		while (!p.empty()) {//将队列清空,或者在这个循环里面创造队列
			p.pop();//这样循环一次创建一次,都不用清空
		}
		for (i = 1; i <= n; i++) 
			cin >> arr[i];
		for (j = 1; j <= m; j++) {
				cin >> brr[j];
				node[brr[j]] = 1;//mqj的数都标记1
		}
		brr[m + 1] = 0;
		brr[m + 2] = MAX;//将这两个数放进去再排序
		sort(arr + 1, arr + n + 1);
		sort(brr + 1, brr + 3 + m);
		for (i = 1; i <= n; i++) {
			if (!node[arr[i]])
			{
				p.push(arr[i]);//将与mqj不重合的数放进队列
			}
		}
		ll len = unique(brr + 1, brr +m+ 3) - (brr+1);//看前面给的链接,有解释
		//去除重复元素并返回非重复元素的下个地址减去首地址等于长度
		ll ans = 0;
		for (i = 2; i <= len; i++) {
			ll num = 0;
			while (!p.empty()) {
				if (p.front() > brr[i - 1] && p.front() < brr[i]) {
					num++;
					p.pop();//在此区间就加一个数,找到最多的数就是答案
				}
				else break;
			}
			ans = max(ans, num);
		}
		if (ans == 0)cout << "Impossible" << endl;
		else cout << ans << endl;
	}
	return 0;
}

题目5排名统计

网址在这-> 题目5排名统计

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我已经怒不可遏了!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值