2022 8.23
唉唉,每题都写一个太累了,写成一个吧
由于我太逊了(真的,要不是我比有些人多学一会。。。)有的题看了题解也不会改,欣赏题面吧
T1
神仙题,求序列众数,但序列超级大(1e6,而且数的范围有2e9大小)
输入如果不优化都超时,std跑了4s(有个人O(nlogn)的解加了快读既然比std跑得快,大雾)
其实不需要用桶存储,先让我们看看题解:
因为题目中说了众数一定存在,所以我们假设我们当前枚举的这个数就是众数,既然这个数是众数,那么他出现的次数一定比其他所有数都多。
对于第一个数,那么在这之前它本身就是众数,如果下一个数和他相等,那么次数+,如果不等,次数-1,如果次数<0,说明众数肯定在后面还会有,那么我们就把当前这个数当做众数,继续去做,这样只要有众数,这样做一定是正确的。
P.S.众数:出现最多次数的数,在此题中是出现次数大于总数一半的数,且保证众数是唯一的
理解理解?
其实最难理解的就是为什么不把当前输入的数存起来,难道这样不会忽略掉一些数吗?
让我们举个栗子(我不会数学证明)
1.例如某一个数是众数,而他后面跟了很多非众数(都不相同)
e.g:5 5 5 5 5 5 1 2 3 4 ...
a)若后面的其他数数量不超过众数的出现次数,则对答案不产生影响
b)若超过了众数出现次数,根据这题的定义,则这个序列不合法
2.例如众数是分散出现的
e.g:5 3 5 3 5 3 5 3 2 3 5 5 5 3...
把数组按照每一个众数分段,把上面1的结论推广到下面,可以说明:
要么众数能完全覆盖其他数,要么序列不合法
总的来说,由本题中众数要求出现n/2次以上,可推知:
1.即使把其他所有数全部连在一起也不可能盖过众数;
2.即使把别的数分开逐一抵消众数,也至少有一个块无法盖过众数。
故此解法成立。证明完毕。(好像我写了一大堆废话?包括这句。。)
AC Code
#include<bits/stdc++.h>
using namespace std;
int t;
int main(){
cin>>t;
while(t--){
int n;cin>>n;
int cnt=-1,cs=-90;
for(int i=1;i<=n;i++){
int tmp;cin>>tmp;
if(cnt<0) cs=tmp,cnt=0;
if(tmp==cs) cnt++;
else cnt--;
}
cout<<cs<<endl;
}
}
T2
先上代码。带上代码看题目也许会简单一点。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
struct person{
int t,w,id;
bool ok;
friend bool operator <(person a,person b){
return (a.w-a.t)>(b.w-b.t);
}
}s[N];
bool cmp(person a,person b){
return (a.t!=b.t?a.t>b.t:a.id<b.id);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i].t>>s[i].w;
s[i].id=i;s[i].ok=1;
}
int ans=0x3f3f3f3f,rnk=0,pos=1,npos=1;
priority_queue<person> a;
sort(s+1,s+1+n,cmp);
while(s[pos].id!=1){
a.push(s[pos]);
pos++;rnk++;
}
rnk++;npos=pos+1;ans=rnk;
while(!a.empty()){
ans=min(ans,rnk);
// printf("ANS %d\n",ans);
person ln=a.top();a.pop();
if(ln.w-ln.t+1>s[pos].t) break;
// printf("Chose %d,%d,%d\n",ln.id,ln.t,ln.w);
rnk--;
s[pos].t-=(ln.w-ln.t+1);
for(;npos<=n;npos++){
// printf("What(%d)->ID[%d][L%d][R%d](%d)\n",npos,s[npos].id,s[npos].t,s[npos].w,a.size());
if(s[npos].t>s[pos].t){
a.push(s[npos]);
}else break;
}
rnk=a.size()+1;
}
cout<<ans;
}
题目描述
【问题描述】
我们现在举行了一场搬砖比赛,其中第i 个人能搬的重量上限是w[i],
如果第i 人搬的砖的重量超过了w[i]的话,那么这个人会因为搬不动了而放
弃比赛,每一个人初始时搬的砖的重量为t[i]。保证初始的t[i]<=w[i],也就
是初始每一个人都不会因为搬不动而退赛。
其中一个人的排名是:比他搬的砖重的人数加一。
1 号选手是氪金玩家,我们希望1 号选手的排名尽量靠前,一号选手通
过充钱获得了一个技能,就是可以把自己搬的砖分给不同的人,但是他自
己搬的砖就会减少,通过让别人搬不动而退赛使得自己的排名上升,注意
别的选手是不能有这个操作的。
【输入格式】
第一行一个整数n
接下来n 行,每行两个整数t[i],w[i],分别表示第i 号选手初始搬砖重
量和重量上限
【输出格式】
输出一行,一个数,表示1 号选手能取得的最高成绩。
【输入样例1】
8
20 1000
32 37
40 1000
45 50
16 16
16 16
14 1000
2 1000
【输出样例1】
3
【输入样例2】
7
4 4
4 4
4 4
4 4
4 4
4 4
5 5
【输出样例2】
2
【数据范围】
对于30%的数据,n<=10;
对于50%的数据,n<=50;
对于100%的数据,1<=n<=10^5,0<=t[i],w[i]<=10^9
怎么样,标准贪心是吧。先上官方题解。
一看数据范围就是 nlong 的算法,先回忆下 nlong 的算法有哪些,无外乎就哪几种数据结构,还有一些分治类算法。
首先思考?怎么才能让排名上升?把砖给其他人然后让其他人爆掉,给谁呢?肯定是排名在他之前的人,具体给谁呢?反正都最多上升一名,给的砖越少越好,所以给wi-ti 最小的人。
关键问题是:给了别人砖,他的排名可能会掉,因为他的砖的数量减少了。那么直接贪心对不对呢?
如果可以让后面爆掉并且排名上升 1 就给,否则就不给。
错误的,因为就算当时排名下降以后还是可以升回来的,很容易举反例。所以我们还可以继续尝试。那么我们就要把初始时排名在他后面,但是他给了别人砖之后排名在他前面的人也拿过来,再从中选择一个 wi-ti 最小的同学。
什么时候结束呢?当他无论怎么给别人砖排名都没法上升的时候就结束了。所以怎么维护我们每次给砖的人呢?
讲解亿下
总的来说,搞一个比自己弱的人在目前来说是一点用都没有还浪费砖,但这不意味这我们以后不会搞他。现在只有搞比自己高的人才能获利,但是不论搞那个高的人都只会带来至多1的收益,甚至还会因为给出了砖而排名下降。
但是我们分析一下,在此时,不论是获利还是落后,我们都希望尽量给出的砖少,因此我们可以取当前比自己大的人中上限于当前最小的一个(落后是无法改变的,因为如果最小的花费都会导致落后,那更大的就更落后)
所以我们想到可以使用堆来维护:
1.push所有比他大的
2.检查堆顶是否可以搞,无论如何,弹出堆头(为了可以结束)
3.检查是否有新的比自己当前大的人,如有,入队
4.更新当前答案为堆的大小+1(记得加一)
5.若堆为空,结束
===end of solution===
其实今天有4道题,但我逊爆了不会做,唉。。。
如果文章有任何谬误,欢迎指出。
upd:2022/8/23 Tue 21:30 hzx:贺题去啦
感言
我太逊了
EOF
本文来自博客园,作者:haozexu,转载请注明原文链接:https://www.cnblogs.com/haozexu/p/18281791

浙公网安备 33010602011771号