#~~
# B 内卷
题目:
期末有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的值
样例输入 Copy
3
1 10000
1 10000
1 10000
样例输出 Copy
3
提示
样例2:
输入
4
1 2
2 2
2 4
3 4
输出
10
感谢王玉大佬!
题意:
在我得到分最多的情况下,还要最轻松,学校得到的总分还要高(一切为了升学率)
思路:
首先排出名次,在依次加上对应名次的最小值。
(主要看代码)
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
struct people{
long long int l,h;
}a[100005];
bool cmp1(people x,people y){
return x.h<y.h;
}
bool cmp2(people x,people y){
return x.l>y.l;
}
int main()
{
map<int,int>li;
long long int s=0;
long long int n,i,min,max;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i].l>>a[i].h;
li[a[i].h]++; //用map标记最大值出现的次数
}
sort(a,a+n+1,cmp1);//排出名次
min=0; //用min追踪最低字数
for(i=1;i<=n;i++){
if(li[a[i].h]==1){ //如果只出现一次,可以直接判断
if(a[i].l<=min){
s+=min; //如果名次高的字数比后一名小,则并列名次, (名次没变,总分提高)
}
else {
s+=a[i].l;
min=a[i].l;
}
}
else { //如果出现多次,则需要算出其中最小字数最大的
sort(a+i,a+i+li[a[i].h],cmp2);
if(a[i].l<=min){
s=s+min*li[a[i].h];
i=i+li[a[i].h]-1;
}
else {
s=s+a[i].l*li[a[i].h];
min=a[i].l;
i=i+li[a[i].h]-1;
}
}
}
cout<<s<<endl;
return 0 ;
}
E 排行统计
题目:
上周周赛结束了,每个同学都有一个排名,且不存在并列情况
zks在统计协会周赛排名的时候,意外的将一部分同学排名统计错了。
请问,zks将所有同学排名都统计错误的情况有多少种?
输入
第一行输入为一个整数n,代表有n名同学
1≤n≤15
输出
所有同学排名都统计错误的情况数量
样例输入 Copy
3
样例输出 Copy
2
提示
n=3时,有两种情况:
3 1 2
2 3 1
题意:使每个人不在他原来的位置上有多少种排法。
思路:错排公式yyds
错排快速通道:点我!点我!!!
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
int main()
{
long long int n,a[20],i;
cin>>n;
a[1]=0;a[2]=1;
for(i=3;i<=15;i++){
a[i]=(i-1)*(a[i-1]+a[i-2]);
}
cout<<a[n]<<endl;
return 0;
}
D题 山不平何以平天下
题目:
刘俊学长在一个深山老林里冒险,这里到处都是山,第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
输出
在释放魔法后,刘俊最少会讨厌的山的数量
样例输入 Copy
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
样例输出 Copy
1
0
2
题意:
找到所以大于它前面并且大于它后面的数,只消除一个数,判断消除后,还有多少个这样的数。
思路:
挺简单的,自己用草稿纸列举各种情况判断出来就ok,就是有点麻烦。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
int n,a[100005],i,book[100005]={0};
int main()
{
int flag1=0,flag2=0,sum=0;
while(cin>>n){
flag1=0;flag2=0;sum=0;
memset(a,0,sizeof(a));
memset(book,0,sizeof(book));
for(i=1;i<=n;i++){
cin>>a[i];
}
for(i=2;i<=n-1;i++){
if(a[i]>a[i-1]&&a[i]>a[i+1]){
book[i]=1;sum++;//用book数组标记满足条件的山的位置
}
}
for(i=2;i<=n-1;i++){
if(book[i]==1&&book[i+2]==1){//如果俩座上近乎连在一起,消去中间的山,就有可能一次消除俩个
if(a[i]==a[i+2]){
flag1=1;break;
}
else flag2=1;//如果一大一小,消去中间的山就必可以消去一座
}
else if(book[i]==1){//消除满足条件的山自身的各种情况
if(a[i-2]>a[i]||a[i+2]>a[i])flag2=1;
if(a[i-1]<a[i-2]&&a[i+1]<a[i+2])flag2=1;
if(a[i-1]>a[i-2]&&a[i-1]<a[i+1]&&a[i+1]<a[i+2])flag2=1;
if(a[i+1]>a[i+2]&&a[i-1]>a[i+1]&&a[i-2]>a[i-1])flag2=1;
if(a[i+1]==a[i-1])flag2=1;
}
}
if(flag1==1)sum-=2;
else {
if(flag2==1)sum--;
}
cout<<sum<<endl;
}
return 0;
}