P2587 [ZJOI2008] 泡泡堂
题目描述
第 XXXX 届 NOI 期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由 n n n 名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂。每一场比赛前,对阵双方的教练向组委会提交一份参赛选手的名单,决定了选手上场的顺序,一经确定,不得修改。比赛中,双方的一号选手,二号选手……, n n n 号选手捉对厮杀,共进行 n n n 场比赛。每胜一场比赛得 2 2 2 分,平一场得 1 1 1 分,输一场不得分。最终将双方的单场得分相加得出总分,总分高的队伍晋级(总分相同抽签决定)。
作为浙江队的领队,你已经在事先将各省所有选手的泡泡堂水平了解的一清二楚,并将其用一个实力值来衡量。为简化问题,我们假定选手在游戏中完全不受任何外界因素干扰,即实力强的选手一定可以战胜实力弱的选手,而两个实力相同的选手一定会战平。由于完全不知道对手会使用何种策略来确定出场顺序,所以所有的队伍都采取了这样一种策略,就是完全随机决定出场顺序。
当然你不想这样不明不白的进行比赛。你想事先了解一下在最好与最坏的情况下,浙江队最终分别能得到多少分。
输入格式
输入文件的第一行为一个整数 n n n,表示每支代表队的人数。
接下来 n n n 行,每行一个整数,描述了 n n n 位浙江队的选手的实力值。
接下来 n n n 行,每行一个整数,描述了你的对手的 n n n 位选手的实力值。
输出格式
输入文件中包括两个用空格隔开的整数,分别表示浙江队在最好与最坏的情况下分别能得多少分。不要在行末输出多余的空白字符。
输入输出样例 #1
输入 #1
2
1
3
2
4
输出 #1
2 0
输入输出样例 #2
输入 #2
6
10000000
10000000
10000000
10000000
10000000
10000000
0
0
0
0
0
0
输出 #2
12 12
说明/提示
样例说明
1:我们分别称 4 4 4 位选手为 A , B , C , D A,B,C,D A,B,C,D 。则可能出现以下 4 4 4 种对战方式,最好情况下可得 2 2 2 分,最坏情况下得 0 0 0 分。
| 浙江 | ??? | 结果 | 浙江 | ??? | 结果 | 浙江 | ??? | 结果 | 浙江 | ??? | 结果 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 一号 | A | C | 负 | A | D | 负 | B | C | 胜 | B | D | 负 |
| 二号 | B | D | 负 | B | C | 胜 | A | D | 负 | A | C | 负 |
| 得分 | 0 | 2 | 2 | 0 |
2:对手都是认真学习的好孩子,不会打游戏。无论如何排列出场顺序都无法改变被蹂躏的结果。浙江队总能取得全胜的结果。
20 % 20\% 20% 的数据中, 1 ≤ n ≤ 10 1\leq n\leq 10 1≤n≤10;
40 % 40\% 40% 的数据中, 1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100;
60 % 60\% 60% 的数据中, 1 ≤ n ≤ 1000 1\leq n\leq 1000 1≤n≤1000;
100 % 100\% 100% 的数据中, 1 ≤ n ≤ 100000 1\leq n\leq 100000 1≤n≤100000,且所有选手的实力值在 0 0 0 到 10000000 10000000 10000000 之间。
题解
首先想到肯定是田忌赛马的思路,用己方最弱的选手去对战对方最强的选手(送人头 )但是反例也很好举出,比如:
5
2 3 4 5 6 7
1 2 3 4 5 6
很明显,己方的选手完全可以完胜对方,不需要送人头了,那么这怎么办呢?
思路还是脱胎于田忌赛马,首先将两个数组排序,考虑下面的问题:
- 什么时候可以派最弱的送人头?(是否可以不送人头,做到2分的贡献)
- 我方最强的如何才能做到贡献最大?
对于第一个问题,如果己方最弱可以干过对方的最弱,那么肯定干啊。不然等着被对方干掉? 所以这就是第一种情况,能干就干,那么如果干不掉呢?最弱的贡献只能是碰掉对方最强的,完成使命。
对于第二个问题,我方的最强如果可以干过对方的最强,那么肯定干啊。不然等着对面最强干掉其他队友? 所以情况和上面很像,能干就干。
那么又出现了新的问题,解决这几个问题的顺序是什么呢?
- 如果己方最弱干得过对方最弱,那么干,贡献+=2
- 如果己方最强干得过对方最强,那么干,贡献+=2
- 如果以上的胜利条件都满足不了,那么派最弱的自杀,碰掉对面最强,注意,在这里要判断是否平手,说不定还有一点分呢!
这是对于己方的最好情况,那么最坏情况呢?
把双方换一下不就好了,首先显然,总分是
2
n
2n
2n ,那么己方的最低分就是
2
n
−
对方的最高分
2n-对方的最高分
2n−对方的最高分
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int a[100010];
int b[100010];
int fun1(){
int l=1,r=n;
int x=1,y=n;
int ans=0;
while(l<=r && x<=y){
if(a[l]>b[x]) ans+=2,l++,x++;
else if(a[r]>b[y]) ans+=2,r--,y--;
else ans+=(a[l]==b[y]),l++,y--;
}
return ans;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
sort(a+1,a+1+n);
sort(b+1,b+1+n);
printf("%lld ",fun1());
swap(a,b);
printf("%lld",2*n-fun1());
return 0;
}
P6927 [ICPC 2016 WF] Swap Space
题目描述
你有许多电脑,它们的硬盘用不同的文件系统储存数据。你想要通过格式化来统一文件系统。格式化硬盘可能使它的容量发生变化。为了格式化,你需要买额外的硬盘。当然,你想要买容量最小的额外储存设备以便省钱。你可以按任意顺序格式化硬盘。格式化之前,你要把该硬盘上所有数据移到一个或更多的其他硬盘上(可以分割数据)。格式化后,该硬盘可以立刻开始使用。你没有必要把数据放到它原来所在的硬盘上。数据也可以被放到你额外买的硬盘上。举个例子,假设你有4个硬盘A、B、C、D,容量分别为6、1、3、3(GB)。新的文件系统下,它们的容量变为6、7、5、5(GB)。如果你只买1GB额外空间,你可以把B硬盘的数据放过去然后格式化硬盘B。现在你的B硬盘有7GB容量了,那么你就可以把A的数据放过去然后格式化A,最后把C、D的数据放到A上,再格式化C和D。
输入格式
第一行一个数 n ( 1 ≤ n ≤ 1 , 000 , 000 ) n(1≤n≤1,000,000) n(1≤n≤1,000,000),表示你的硬盘数。接下来 n n n 行,每行两个数 a a a 和 b b b,分别表示该硬盘的原容量和新文件系统下的容量。所有容量都以 GB 为单位,且 1 ≤ a , b ≤ 1 , 000 , 000 , 000 1≤a,b≤1,000,000,000 1≤a,b≤1,000,000,000。
输出格式
输出如果要格式化所有硬盘,你最少需要购买多少额外空间(GB)。
输入输出样例 #1
输入 #1
4
6 6
1 7
3 5
3 5
输出 #1
1
输入输出样例 #2
输入 #2
4
2 2
3 3
5 1
5 10
输出 #2
5
题解
显然需要把所有的硬盘排序,那么如何排序?
显然要按 a i , b i a_i,b_i ai,bi 的大小关系分类:
- a i < b i a_i < b_i ai<bi:
假令有两对数 ( a 1 , b 1 ) , ( a 2 , b 2 ) (a_1,b_1),(a_2,b_2) (a1,b1),(a2,b2),且 a 1 ≤ a 2 a_1 \leq a_2 a1≤a2。
-
如果 b 1 ≥ a 2 b_1 \geq a_2 b1≥a2。则按照 12 的顺序,将带来 a 1 a_1 a1 的花费;而按照 21 的顺序,将带来 a 2 a_2 a2 的花费。所以按照 12 顺序更优。
-
如果 b 1 < a 2 b_1 < a_2 b1<a2。则按照 12 的顺序,将带来 a 1 + a 2 − b 1 a_1 + a_2 - b_1 a1+a2−b1 的花费;而按照 21 的顺序,将带来 a 2 a_2 a2 的花费。因为 a 1 − b 1 < 0 a_1 - b_1 < 0 a1−b1<0,所以按照 12 顺序更优。
综上,此时按照 a i a_i ai 从小往大排序正确。
- a i > b i a_i > b_i ai>bi:
假令有两对数 ( a 1 , b 1 ) , ( a 2 , b 2 ) (a_1,b_1),(a_2,b_2) (a1,b1),(a2,b2),且 b 1 ≥ b 2 b_1 \geq b_2 b1≥b2:
-
如果 b 1 ≥ a 2 b_1 \geq a_2 b1≥a2。则按照 12 的顺序,将带来 a 1 a_1 a1 的花费;而按照 21 的顺序,将带来 a 2 + a 1 − b 2 a_2 + a_1 - b_2 a2+a1−b2 的花费。因为 b 2 − a 2 < 0 b_2 - a_2 < 0 b2−a2<0,所以按照 12 顺序更优。
-
如果 b 1 < a 2 b_1 < a_2 b1<a2。则按照 12 的顺序,将带来 a 1 + a 2 − b 1 a_1 + a_2 - b_1 a1+a2−b1 的花费;而按照 21 的顺序,将带来 a 2 + a 1 − b 2 a_2 + a_1 - b_2 a2+a1−b2。因为 b 2 − b 1 < 0 b_2 - b_1 < 0 b2−b1<0,所以按照 12 顺序更优。
综上,此时按照
b
i
b_i
bi 从大往小排序正确。
以上证明摘自这篇文章
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int a1,b1;
}a[1000010],b[1000010];
int t;
int n,m;
bool cmp(node xx,node yy){
return xx.a1<yy.a1;
}
bool cmp2(node xx,node yy){
return xx.b1>yy.b1;
}
signed main(){
while(~scanf("%lld",&t)){
for(int i=1;i<=t;i++) a[i]={0,0},b[i]={0,0};
n=0,m=0;
for(int i=1;i<=t;i++){
int x,y;
scanf("%lld%lld",&x,&y);
if(x<=y){
a[++n].a1=x;
a[n].b1=y;
}else{
b[++m].a1=x;
b[m].b1=y;
}
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+m+1,cmp2);
int sum=0,ans=0;
for(int i=1;i<=n;i++){
ans=min(ans,sum-a[i].a1);
sum+=(a[i].b1-a[i].a1);
}
for(int i=1;i<=m;i++){
ans=min(ans,sum-b[i].a1);
sum+=(b[i].b1-b[i].a1);
}
printf("%lld\n",abs(ans));
}
return 0;
}
P4053 [JSOI2007] 建筑抢修
题目描述
小刚在玩 JSOI 提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T 部落消灭了所有 Z 部落的入侵者。但是 T 部落的基地里已经有 N N N 个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T 部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
输入格式
第一行,一个整数 N N N。
接下来 N N N 行,每行两个整数 T 1 , T 2 T_1,T_2 T1,T2 描述一个建筑:修理这个建筑需要 T 1 T_1 T1 秒,如果在 T 2 T_2 T2 秒之内还没有修理完成,这个建筑就报废了。
输出格式
输出一个整数 S S S,表示最多可以抢修 S S S 个建筑。
输入输出样例 #1
输入 #1
4
100 200
200 1300
1000 1250
2000 3200
输出 #1
3
说明/提示
对于 100 % 100 \% 100% 的数据, 1 ≤ N < 150000 1 \le N < 150000 1≤N<150000, 1 ≤ T 1 < T 2 < 2 31 1 \le T_1 < T_2 < 2^{31} 1≤T1<T2<231。
题解
较简单的排序题,有人叫他反悔贪心
这道题目怎么反悔呢?
很明显按照修理建筑的T2排序,那么如果遇到不能修的呢?
反悔!
反悔也是要贪心的,反悔的一定是在这及之前T1最大的建筑,用一个优先队列维护就可以了
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
struct node{
int x,y;
}a[150010];
bool cmp(node xx,node yy){
if(xx.y==yy.y) return xx.x<yy.x;
return xx.y<yy.y;
}
priority_queue<int>q;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y);
sort(a+1,a+1+n,cmp);
int k=0;
int cnt=0;
for(int i=1;i<=n;i++){
k+=a[i].x;
q.push(a[i].x);
if(k<=a[i].y){
cnt++;
}else{
k-=q.top();
q.pop();
}
}
printf("%lld",cnt);
return 0;
}
P8113 [Cnoi2021] 自我主义的平衡者
题目背景
「流浪月球 ~ The Wandering Moon」在幻想乡上映了。
正如一千个人心中有一千个哈姆雷特,关于它的争议也在悄然蔓延。
不知何时起,一个叫做「花瓣」的平台出现,慢慢取代了市井之中的讨论声,成为了争议的主战场——因为它具有评分功能。平台上旁征博引、各抒己见的评分帖成为了幻想乡的居民们日常,一切看起来岁月静好。
直到平衡者的出现。
起初没有人在意在意这缕杂音,这只不过是一种无心的叛逆,一点无奈的情感,一次无聊的宣泄。直到平衡的思想深入人心,自我主义的狂潮达到顶峰,评分系统的秩序几近崩溃。
Cirno 觉得自己该做些什么了。
题目描述
Cirno 决定通过计算来说服与拯救被自我主义裹挟的众人。
参与评分的共有 n n n 位居民,平台限制的最高分为 m m m。
每个居民在评分前都有一个心理预期分数 a i ( a i ∈ [ 0 , m ] ∩ Z ) a_i(a_i\in[0,m]\cap\mathbb{Z}) ai(ai∈[0,m]∩Z)。
但人们并不会按照心理预期分数直接评分,而是当当前平台上的平均分严格高于自己的心理预期分数时,便评分道「分数太高了,打个 0 0 0 分平衡一下」,反之则说「分数太低了,打个满分( m m m分)平衡一下」。
初始时平台上的平均分为 0 0 0。
为了证明这种评分方式对公平的破坏性,Cirno 希望你计算出这 n n n 位居民在不同的排列顺序下评分,平台上最终平均分可能的最大值与最小值。
输入格式
第一行,两个整数,用空格隔开,表示 n n n, m m m。
第二行, n n n 个整数,用空格隔开,表示 { a n } \{a_n\} {an}。
输出格式
一行,两个实数,保留两位小数,分别表示平均分最大值和最小值。
输入输出样例 #1
输入 #1
5 5
1 2 3 4 5
输出 #1
4.00 2.00
输入输出样例 #2
输入 #2
7 114
23 75 35 17 101 55 73
输出 #2
81.43 32.57
说明/提示
数据范围与约定
对于 100 % 100\% 100% 的数据保证, 1 < n , m ≤ 1 0 5 1 < n,m\le 10^5 1<n,m≤105, a i ∈ [ 0 , m ] a_i \in [0,m] ai∈[0,m]。
子任务
Subtask1(10 points): n ≤ 8 n \le 8 n≤8。
Subtask2(10 points): n ≤ 20 n \le 20 n≤20。
Subtask3(30 points): n ≤ 1 0 3 n \le 10^3 n≤103。
Subtask4(50 points):无特殊限制。
题解
直觉题,直接按照大小排序,瞎搞一通就行
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int a[100010];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+n);
int sum=0;
double k=0;
for(int i=1;i<=n;i++){
if(k<a[i]*1.0 || abs(a[i]*1.0-k)<(1e-7)) sum+=m;
k=sum*1.0/i;
}
printf("%.2lf ",k);
reverse(a+1,a+1+n);
sum=0;
k=0;
for(int i=1;i<=n;i++){
if(k<a[i]*1.0 || abs(a[i]*1.0-k)<(1e-7)) sum+=m;
k=sum*1.0/i;
}
printf("%.2lf ",k);
return 0;
}
257

被折叠的 条评论
为什么被折叠?



