[洛谷P2397]yyy loves Maths VI (mode)

题目传送门

这道题题面十分简单,貌似不难,但空间一限制就比较麻烦了。

其实了解了一些比较重要的东西就很简单了。

先不切入重点。

方法一

如果一个数过半,如果将这个数转成二进制的形式,则该数对应的每位上的数(不是$0$就是$1$)一定过半(指其他数的对应数位$0$或$1$的统计)。

举个例子:有一串数列$\{ 2,2,3,2,1,2\}$。把每个数换成二进制即为:

$10$、$10$、$11$、$10$、$01$、$10$。

发现第一位$1$出现比$0$次数多,第二位$0$比$1$多。所以过半的数的二进制为$10$、即为$2$。

这个方法比较冷门,好像并无卵用常数较大但能过(过了读入毒瘤即可)。

方法二

步入正解:摩尔投票法

步骤:

(1)两个变量:$now\_num$、$count$;

(2)读入数$val$;

(3)如果$val$不等于$now\_num$,让$count$自减。如果本来$count$为$0$,标记$now\_num$为$val$并让$count$为1;

(4)否则$count$自加;

(5)重复步骤(2)。

正确性:会发现对于每一个$val$都会抵消掉一个不等于它的$val$,而所求的数过半,所以这个数会抵消掉其他所有数且还有过剩的。

注意这个性质具有可加性。也就是可以用线段树等数据结构维护。

假如求过了三分之一的数呢?有摩尔投票法的扩展。

然而我太弱了不知道其实就是搞两个$now\_num$和$count$弄一下。

最后这道题要注意读入快读啥的都挂了,必须要$scanf$才不被卡原理玄学。

 1 int n, v, x, cnt = 0;
 2 
 3 int main() {
 4     scanf("%d", &n);
 5     rep(i, 1, n) {
 6         scanf("%d", &x);
 7         if (cnt == 0) v = x;
 8         cnt += v == x ? 1 : -1;        
 9     }
10     printf("%d", v);
11     return 0;
12 }

 

posted @ 2019-02-12 21:22  AC-Evil  阅读(164)  评论(0编辑  收藏  举报