首页 > 其他分享 >「博弈&位运算」投票游戏

「博弈&位运算」投票游戏

时间:2023-01-09 16:14:19浏览次数:37  
标签:同学 状态 博弈 运算 踢掉 投票 当前 僵持

本题为1月7日22寒假集训每日一题题解

题目来源:(未知)

题面

题目描述

信奥班的同学总是这么无聊,他们现在喜欢玩一种投票游戏。

游戏规则如下,把参与游戏的同学们编号由1到N,然后他们开始投票,每个人只能投一票,只能是赞成或者反对,投票结果下来后如果赞成人数严格大于反对的人数,那么编号最小的那位同学便被踢出游戏,剩下的同学继续开始投票,直到投票僵持下来(比如剩两个人的时候一个人反对一个人赞成就会一直僵持下去),这时候游戏结束。

熊教准备了一些小红花,会把他们平均分给这些剩下的同学。每个同学都想得到最多的小红花,而且不想自己被踢出。给出同学个数N,问最后剩下的同学个数,假定信奥班的同学都无比机智。

输入

一行,一个整数N

输出

一行,一个整数表示剩下的同学个数。

样例输入

3

样例输出 Copy

2

提示

30% 1<=n<=50.

100% 1<=n<=5000.


思路分析

显然这是一道博弈论的题目,不过本题不同于二人博弈的规则,不好直接编写动态规划的代码,所以需要我们手动进行状态转移并寻找规律.

如果还剩一个人,显然他一直赞成即可不让自己被踢掉,属于僵持状态,此时答案为1.

如果当前还剩两个人,显然第一个人一直反对即可不让自己被踢掉,属于僵持状态,此时答案为2.

如果当前还剩三个人,无比机智的第二个人和第三个人会发现,如果把第一个人踢了,在人数减少的同时可以进入僵持状态,自己能稳定拿到更多的糖果,所以会联手一起赞成把第一个人踢掉,转移到还剩两人的僵持状态,此时答案为2.

如果当前还剩四个人,虽然无比机智的第三个人和第四个人会联手,企图把第一个和第二个人踢掉来达到人数更少的僵持状态,但是同样无比机智的第二个人会发现,一旦第一个人被踢了,那么就会进入并不僵持的三人状态,此时他一定会被联手踢掉,所以想要获得糖果,就必须和第一个人联手一起反对,在防止第一个被踢掉的同时,防止自己被踢掉.因此此时不会有任何一个人能够被踢掉,属于僵持状态,此时答案为4.

剩下同理分析,会发现只有当前人数是前一个僵持状态的2倍时(有足够的人联手反对),才能维持成一个新的僵持状态.也就是说,只有当前人数为2的非负整数幂时,才是僵持状态,而其他状态一定会转移到最接近的小于当前人数的僵持状态.

找到了上述的规律后,此题就转化成求最近的小于当前数的2的一个非负整数幂是多少了.要解决这个问题,可以直接枚举2的倍数,直到大于当前数即可;也可以借助位运算,由于2的一个非负整数幂的二进制只有一个1,所以只需要让当前数不断与上当前数减一,把低位的1全部消掉即可.

这里我采用的是效率更高的位运算的写法.

参考代码

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
 
#include <iostream>
#include <algorithm>
 
using namespace std;
 
int main()
{
    ios::sync_with_stdio(false);
 
    int n;
    cin >> n;
 
    // 不断与上当前数减一,消掉低位的1,直到只剩一个1(只剩一个1时,再与一次的结果就会是0,以此作为循环条件即可,注意位运算的优先级很低)
    while (n & (n - 1))
    {
        n &= n - 1;
    }
 
    cout << n << "\n";
 
    return 0;
}

"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德

标签:同学,状态,博弈,运算,踢掉,投票,当前,僵持
From: https://www.cnblogs.com/geministar/p/zstu22_1_7.html

相关文章

  • Shell 基本运算符
    Shell和其他编程语言一样,支持多种运算符,包括:算数运算符关系运算符布尔运算符字符串运算符文件测试运算符原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如awk......
  • 关系运算符shell
    关系运算符只支持数字,不支持字符串,除非字符串的值是数字。下表列出了常用的关系运算符,假定变量a为10,变量b为20:运算符说明举例-eq检测两个数是否相等,相等返回true。[......
  • 布尔运算符shell
    下表列出了常用的布尔运算符,假定变量a为10,变量b为20:运算符说明举例!非运算,表达式为true则返回false,否则返回true。[!false]返回true。-o或运算,有一个表达式......
  • 简单位运算
    #include<iostream>intmain(){inta=1;intb=8;std::cout<<(~a)<<'\n';std::cout<<(a<<1)<<'\n';std::cout<<(a<<1|1)<<'\n';std::cout......
  • 2.2JS中的运算符号
    ​ JS中运算符号大部分和java中的运算符一样,我们在这里分析一下特殊的运算符号 关于/%JS中,数字类型都是number,除法的结果中如果没有小数位,直接就是一个整数,如......
  • 2.2JS中的运算符号
    ​ JS中运算符号大部分和java中的运算符一样,我们在这里分析一下特殊的运算符号 关于/%JS中,数字类型都是number,除法的结果中如果没有小数位,直接就是一个整数,如......
  • 【Python】算数运算符的区别
    #算数运算符的区别#数值+布尔真为1假为0print(1+True)#在字符串里面+作为连接符使用print('你'+'好'+'!')#在字符串里面用乘号,输入该字符串三次print('您好\n'*3......
  • 牛客小白月赛65 D-牛牛取石子(博弈论)
    https://ac.nowcoder.com/acm/contest/49888/D题目大意:一共有两堆石子,第一堆a个,第二堆b个,牛牛(先手)和牛妹轮流取石子:2种方案种挑一种1.第一堆取1个,第二堆取2个2......
  • Python基础中的基础:基本运算符的用法
    1算术运算符算术运算符只能用来将同数据类型的进行计算salary=3.3res=salary*12print(10+1)#11print(10-3)#7print(10*3)#30print(10/3)......
  • Java运算符(复习)
    运算符运算符:对字面量或者变量进行操作的符号表达式:用运算符把字面量或者变量连接起来,符合Java语法的式子就可以称为表达式。算数运算符符号作用+加法作用......