给你一个n个数的数列,其中某个数出现了超过n div 2次即众数,请你找出那个数。
给你一个n个数的数列,其中某个数出现了超过n div 2次即众数,请你找出那个数。
第1行一个正整数n。
第2行n个正整数用空格隔开。
一行一个正整数表示那个众数。
100%的数据,n<=500000,数列中每个数<=maxlongint。
zju2132 The Most Frequent Number
鸣谢 黄祎程
啊这真是个神奇的东西。。。
不严密而不严谨的题解:
根据题目的规定,出现最多的数出现次数一定是总数的一半以上。在这里我用tmp记录当前的答案,用t来表示当前答案从记录的地方开始比不是这个答案的多的个数。
这样说可能比较难懂。但是下面我们来模拟一组数据:
8
2 3 3 2 3 3 2 3
首先我们读入样例的总数n=8,然后读入第一个数据2.下面我们暂且把2号妹子当做答案。那么现在我们就相当于从第一个数开始选择到第一个数,现在这些数中和所选的数相同的(即2)有一个,不同的有0个,我们就把t赋值为1。
接下来,我们读入第二个数3,这时不同的数的个数就为1了,于是我们将t自减,变为0。
再然后,我们读入第三个数3,不同数的个数变为2,再自减t,变为-1。这时,我们就决定不选择该数,而选择我们读入的数3记为tmp,将t清空重新计算。
之后一直这样计算,就能得到最后的答案。
不严谨而不严密的证明:即证明对于一组数其中的一个数,总有从其中的一个数字相同的点出发会在后面的判断中始终不改变tmp,且第一个tmp一定是最终的答案。
∵这个数的出现次数大于总次数的一半
我们假设这个最终的答案出现在一个位置。并且在之后会因为不同的妹子太多被覆盖。
那么,不同的数的个数一定大于这个最终的答案数。
∴在下一次这个数出现时,这个数的剩余总个数一定仍然超过剩余数的总个数的一半。
∴以此类推,最终能够得到答案
#include "stdio.h" using namespace std; inline void read(int & v){ char ch;int poi=1;while(ch=getchar(),ch!='-'&&(ch>'9'||ch<'0')); if(ch=='-')poi=-1,ch=getchar();v=0; while(ch<='9'&&ch>='0')v=v*10+ch-'0',ch=getchar(); v*=poi;} main(){int n,i,tmp,t=1,q;read(n),read(tmp); for(i=2;i<=n;i++){read(q);if(q==tmp)++t;else --t;if(t<0)tmp=q,t=1;} printf("%d",tmp);}