[洛谷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 }