数学3(博弈+splya)

标签: 数学


hdu_5194 (打表找规律)

  • 题意

有n和黑球和m个白球,现在一个个的取出这些球,如果是黑球则当前标记为1,白球为0,那么当取完这些球会得到一些序列。问你在所有的序列中出现01这个子序列的期望

  • 题解

首先要掌握一种技能就是可以通过打表找规律的方式解题,因为真的有很多的题都是这么解出来的。打表有一个很好的习惯

如果用手打表的话,最好列出一个n*m的表格,将对应的n和m的值填入对应的格子,这样最后比较容易可以看出规律这个题就是打表做的,规律是什么直接看代码吧

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. int gcd(int a, int b)
  6. {
  7. return b==0?a:gcd(b,a%b);
  8. }
  9. int main()
  10. {
  11. int n,m;
  12. while(~scanf("%d%d",&n,&m))
  13. {
  14. int fm = n+m;
  15. int fz = n*m;
  16. int tm = gcd(fz,fm);
  17. printf("%d/%d\n",fz/tm,fm/tm);
  18. }
  19. return 0;
  20. }

hdu_5366 (dp)

  • 题意

要在一个1~N的区间里,放置一种东西,每个东西占据一个单位区间,要求两个东西之间的距离大于等于2,问你有几种放法

  • 题解

这个是一个很典型的dp问题

dp[i] 表示放置到第i个位置的时候的放置种类数

那么有第i个位置可以放一个,其他的位置都不放,那么多出这个位置就多出了一种情况,还有就是如果这一位不放那么就是dp[i-1],如果放的话,就是dp[i-3]+1;

\(dp[i] = dp[i-1]+1+dp[i-3]\)

很简单吧,做题的时候相信自己可以做出来就可以肆意ac了

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. #define ll long long
  6. ll dp[66];
  7. void init()
  8. {
  9. dp[1] = 1;
  10. dp[2] = 2;
  11. dp[3] = 3;
  12. for(int i = 4; i < 66 ; i++)
  13. {
  14. dp[i] = dp[i-1]+1+dp[i-3];
  15. }
  16. }
  17. int main()
  18. {
  19. int n;
  20. init();
  21. while(~scanf("%d",&n))
  22. {
  23. printf("%lld\n",dp[n]);
  24. }
  25. return 0;
  26. }

好了,下面要开始学习一下博弈了

注意,博弈的核心是sg还有打表,模拟找规律

hdu_3951 一个简单的博弈

  • 题意

有一圈数字收尾相连,你可以拿编号相连的数字,注意,头尾的数字也可以看成是相连的。每次只能拿1~k的个数个数字,最后不能拿得输掉

  • 题解

其实有很多的博弈都是根据对称性,你可以考虑一下,这个题,首先,如果\(k>n\)的时候就可以第一个人都取完,那么第二个人输掉了

再考虑到如果k = 1的话,直接根据n的奇偶判断就可以了

然后如果n是偶数的话, 第一个人不能取完,那么考虑,如过第一个人拿了超过一半的话,第二个人肯定可以一次性把剩下的都拿走,所以第二个人赢。如果不拿走一半,那么第二个人永远可以模仿着第一个人,在对称的位置上再拿取相同数目的数字,所以仍然是2赢

考虑n是奇数,相同的分析方式可以得出结论就是2赢

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. int main()
  6. {
  7. int T;
  8. scanf("%d",&T);
  9. int cnt = 1;
  10. while(T--)
  11. {
  12. int n,k;
  13. scanf("%d%d",&n,&k);
  14. printf("Case %d: ",cnt++);
  15. if(k>=n) puts("first");
  16. else if(k==1){
  17. if(n%2==1) puts("first");
  18. else puts("second");
  19. }
  20. else puts("second");
  21. }
  22. return 0;
  23. }

hdu_1847 sg

  • 题解

介绍一下sg函数:

定义: 一个状态的sg是它所有的后继状态的所有sg中第一个没有出现的非负整数。

用法: sg函数为0可以指示一个状态,不为0为一个状态,所有石子堆的sg的异或值等于整个石子堆的异或值。

求法:递归的求就可以了,对于有n堆石子,每次拿取的个数有一定的个数,直接用模板就可以。

sg在比赛的时候还可以打表找规律哈哈。这点很重要

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. const int N = 1008;
  7. int sg[N];
  8. int s[11];
  9. int Getsg(int n,int k)
  10. {
  11. int mex[1008];
  12. memset(mex,0,sizeof(mex));
  13. if(sg[n]!=-1) return sg[n];
  14. for(int i = 0; i < k && n-s[i]>=0; i++){
  15. mex[Getsg(n-s[i],k)] = 1;
  16. }
  17. for(int i = 0; ; i++){
  18. if(!mex[i]){
  19. return sg[n] = i;
  20. }
  21. }
  22. }
  23. int main()
  24. {
  25. int n;
  26. memset(sg,-1,sizeof(sg));
  27. sg[0] = 0;
  28. for(int i = 0; i < 11; i++){
  29. s[i] = pow(2.0,(double)i);
  30. }
  31. while(~scanf("%d",&n))
  32. {
  33. if(Getsg(n,11)!=0) puts("Kiki");
  34. else puts("Cici");
  35. }
  36. return 0;
  37. }

hdu_1536 sg

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. int s[108];
  6. int h[108];
  7. int sg[10008];
  8. int Getsg(int n,int k)
  9. {
  10. int mex[108];//注意一定要写在里面。请仔细思考为什么这么做。
  11. memset(mex,0,sizeof(mex));
  12. if(sg[n]!=-1) return sg[n];//因为集合s一致,则每个数量的mex一样,可以重复利用
  13. if(n-s[0]<0) return sg[n] = 0;//s[0]为集合中最小值,n-s[0]<0,则n不可能到达其他状态,一定为P
  14. for(int i = 0; i < k && n-s[i]>=0; i++){
  15. mex[Getsg(n-s[i],k)] = 1;//n的后继SG函数中的没有出现的最小非负数
  16. }
  17. for(int i = 0; ; i++){
  18. if(!mex[i]){
  19. //printf("i = %d\n",i);
  20. return sg[n] = i;
  21. }
  22. }
  23. }
  24. int main()
  25. {
  26. int k;
  27. while(~scanf("%d",&k),k)
  28. {
  29. memset(sg,-1,sizeof(sg));
  30. sg[0] = 0;
  31. for(int i = 0; i < k; i++){
  32. scanf("%d",&s[i]);
  33. }
  34. sort(s,s+k);
  35. int m;
  36. scanf("%d",&m);
  37. for(int i = 0; i < m; i++)
  38. {
  39. int t;
  40. scanf("%d",&t);
  41. int fl = 0;
  42. for(int j = 0; j < t; j++){
  43. scanf("%d",&h[j]);
  44. fl = fl ^ Getsg(h[j],k);
  45. }
  46. if(fl==0) printf("L");
  47. else printf("W");
  48. }
  49. printf("\n");
  50. }
  51. return 0;
  52. }
  53. //http://blog.csdn.net/liwen_7/article/details/7943258

hdu_2516 斐波那契博弈

  • 题解

斐波那契博弈的固定描述

有一堆个数为n的石子,游戏双方轮流取石子,满足:

1)先手不能在第一次把所有的石子取完;

2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。

约定取走最后一个石子的人为赢家,求必败态。

如果当前的数是斐波那契数列中的一个数的话,为一种状态,不是为另一种状态

  • 代码
  1. //斐波那契博弈
  2. //http://blog.csdn.net/acm_cxlove/article/details/7835016
  3. //一般斐波那契数列求到第45个就够了
  4. #include<cstdio>
  5. #include<cstring>
  6. #include<algorithm>
  7. using namespace std;
  8. const int N = 45;
  9. #define ll long long
  10. ll f[N];
  11. void init()
  12. {
  13. memset(f,0,sizeof(f));
  14. f[0] = 1;
  15. f[1] = 2;
  16. for(int i = 2; i <= 45; i++){
  17. f[i] = f[i-1]+f[i-2];
  18. }
  19. }
  20. int main()
  21. {
  22. ll n;
  23. init();
  24. while(~scanf("%lld",&n),n)
  25. {
  26. bool fl = 0;
  27. for(int i = 0; i <= 45; i++){
  28. if(f[i]==n){
  29. fl = 1;
  30. break;
  31. }
  32. }
  33. if(fl) puts("Second win");
  34. else puts("First win");
  35. }
  36. return 0;
  37. }

poj_1286 polya

介绍一下burnside 和 polya

结论:

burnside:

对于一个置换f,若一个着色方案s经过置换后不变,称s为f的不动点,将f的不动点的个数记为 \(C(f)\) 则等价类数目为所有 \(C(f)\) 的平均值

polya:

如果置换f分解成 \(m(f)\) 个循环的乘积,假设k种染色,则有 $C(f) = k^{m(f)} $ 带入burnside,等价类的个数等于所有的置换f的$C(f) = k^{m(f)} $ 的平均数

应用:

所以做题的时候要找到所有的置换

置换要构成置换群,即满足所有置换F中任意两个置换的乘积也应当在F中

然后对于每个置换找到其不动点个数,或者是找到循环节的个数然后带入公式即可

  • 题意

就是一个手镯,用三种颜色图,可以旋转和翻转,求有多少方案。

  • 题解

对于旋转的话有n种置换,每种置换的循环节为gcd(i,n),i是旋转的个数,可以自己找找规律

对于翻转的置换

考虑n是奇数,则对于每个点都有一个对称轴,那么就有n种置换,每种置换的循环节是(n+1)/2

如果n是偶数,那么有n/2中置换是点通过对称轴对应的循环节为(n/2)+1;

有n/2种置换是对称轴不通过点,那么有n/2个循环节

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cmath>
  5. using namespace std;
  6. #define ll long long
  7. ll gcd(ll a, ll b)
  8. {
  9. return b==0?a:gcd(b,a%b);
  10. }
  11. ll Polya(ll n)
  12. {
  13. if(n==0)
  14. return 0;
  15. //旋转
  16. ll c;
  17. ll sum = 0;
  18. for(ll i = 1; i <= n; i++)
  19. {
  20. c = gcd(i,n);
  21. sum+=pow(3.0,(double)c);
  22. }
  23. //翻转
  24. if(n%2==0)
  25. {
  26. sum+=pow(3.0,(double)((n+2)/2))*n/2;
  27. sum+=pow(3.0,(double)n/2)*n/2;
  28. }
  29. else
  30. {
  31. sum+=pow(3.0,(double)((n+1)/2))*n;
  32. }
  33. return sum/(2*n);
  34. }
  35. int main()
  36. {
  37. ll n;
  38. while(~scanf("%lld",&n))
  39. {
  40. if(n==-1) return 0;
  41. printf("%lld\n",Polya(n));
  42. }
  43. return 0;
  44. }

poj_2369 置换

  • 题意

给定一个序列,问需要最少需要置换多少次才能变为有序序列.

*分析

对于每一位,算出最少的置换到自己应该的数字。每一位都有这样的数字,取最小公倍数就可以。对于置换的题一般都去想循环节

  • 代码
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<map>
  5. using namespace std;
  6. #define ll long long
  7. map <ll,ll> m;
  8. bool vis[1004];
  9. ll gcd(ll a, ll b)
  10. {
  11. return b==0?a:gcd(b,a%b);
  12. }
  13. ll lcd(ll a, ll b)
  14. {
  15. return a/gcd(a,b)*b;
  16. }
  17. int main()
  18. {
  19. ll n;
  20. while(~scanf("%lld",&n))
  21. {
  22. m.clear();
  23. ll tm;
  24. for(ll i = 1; i <= n; i++)
  25. {
  26. scanf("%lld",&tm);
  27. m[i] = tm;
  28. vis[i] = 0;
  29. }
  30. ll c;
  31. ll ans = 1;
  32. for(ll i = 1; i <= n; i++){
  33. if(vis[i]!=0){
  34. continue;
  35. }
  36. c = 0;
  37. ll tt = i;
  38. vis[tt] = 1;
  39. while(1)
  40. {
  41. c++;
  42. //printf("tt = %lld\n",tt);
  43. tt = m[tt];
  44. if(vis[tt]!=0) break;
  45. vis[tt] = 1;
  46. }
  47. ans = lcd(c,ans);
  48. // printf("ans = %lld\n",ans);
  49. }
  50. printf("%lld\n",ans);
  51. }
  52. return 0;
  53. }

uva_10733 置换

题意:求用n中颜色涂立方体的不同种数,能旋转到的算一种

题意:和上一题UVA - 10601 Cubes (组合+置换) 的立方体旋转考虑的分类是一样的,不过这里我们考虑的是涂面的情况

1.不变置换(1)(2)(3)(4)(5)(6), 共1个;

2.沿对面中心轴旋转 90度, 270度 (1)(2345)(6), (1)(5432)(6) 同类共 6个;

3.沿对面中心轴旋转 180度 (1)(24)(35)(6), 同类共 3个;

4.沿对角线轴旋转 120度, 240度 (152)(346), (251)(643) 同类共 8个;

5.沿对边中点轴旋转 180度 (16)(25)(43) 同类共 6个;

  1. #include <cstdio>
  2. #include <cstring>
  3. unsigned long long n;
  4. int main() {
  5. while (~scanf("%llu", &n) && n) {
  6. printf("%llu\n", (n * n * n * n * n * n + 12 * n * n * n + 3 * n * n * n * n + 8 * n * n) / 24);
  7. }
  8. return 0;
  9. }

数学3(博弈+splya)的更多相关文章

  1. 醒醒吧!互联网的真正未来不是AI,更不是VR,AR,而是区块链

    这些力量并非命运,而是轨迹.他们提供的并不是我们将去向何方的预测,而是告诉我们,在不远的将来,我们会向那个方向前行,必然而然. ---凯文•凯利 文字与货币 人类在演化过程中,凭借智慧创造了无数事物, ...

  2. UVaLive5059 Playing With Stones

    数学问题 博弈 SG函数 我总觉得这题做过的……然而并没有记录 看上去是一个nim游戏的模型. 手推/打表找一下前几项的规律,发现x是偶数时,sg[x]=x/2,x是奇数时,sg[x]=sg[x di ...

  3. 2017广东工业大学程序设计竞赛决赛 题解&源码(A,数学解方程,B,贪心博弈,C,递归,D,水,E,贪心,面试题,F,贪心,枚举,LCA,G,dp,记忆化搜索,H,思维题)

    心得: 这比赛真的是不要不要的,pending了一下午,也不知道对错,直接做过去就是了,也没有管太多! Problem A: 两只老虎 Description 来,我们先来放松下,听听儿歌,一起“唱” ...

  4. Codeforces Round #651 (Div. 2) C. Number Game (博弈,数学)

    题意:对于正整数\(n\),每次可以选择使它变为\(n-1\)或者\(n/t\) (\(n\ mod\ t=0\)且\(t\)为奇数),当\(n=1\)时便不可以再取,问先手赢还是后手赢. 题解:首先 ...

  5. 【转】ACM博弈知识汇总

    博弈知识汇总 转自:http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍 ...

  6. ACM博弈知识汇总(转)

    博弈知识汇总 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻 ...

  7. nim3取石子游戏 (威佐夫博弈)

    http://www.cnblogs.com/jackge/archive/2013/04/22/3034968.html 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有 ...

  8. 8-14-Exercise(博弈:HDU 1846 & HDU 1527 )

    B.HDU 1846    Brave Game 算是最简单的入门博弈题吧...... 呃......我用的......算是不是方法的方法吧——找规律~ 可以发现:X-M为奇数时,先手会输:而为偶数的 ...

  9. 【POJ1067】取石子游戏 (威佐夫博弈)

    [题目] Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的 ...

随机推荐

  1. Oracle 启动参数

    查看数据库的SID DB_NAME SERVICE_NAME

  2. Linux发行版 CentOS6.5下删除分区操作

    本文地址http://comexchan.cnblogs.com/,作者Comex Chan,尊重知识产权,转载请注明出处,谢谢!   有时候,发现分区分错了.需要删除分区,只需按照分区的步骤逆向操作 ...

  3. 小白的Python之路 day4 软件目录结构规范

    软件目录结构规范 为什么要设计好目录结构? "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题.对于这种风格上的规范,一直都存在两种态度: 一类同 ...

  4. 在QComboBox的基础上实现复选功能

    这个是最近的一个项目上需要实现的功能.要求如下: 下拉列表的项目可以多选 显示框不能编辑 所选中的项目在显示框中出现 下面根据网上的提示代码(参照博客 一去二三里),主要实现如下代码(与参照略有不同) ...

  5. [转]Android sharedpreferences使用

    1.    SharedPerferences保存的数据主要是类似配置信息格式的数据,因此它保存的数据主要是简单类型的key-value对,SharedPreferences本身并没有写入数据的能力, ...

  6. Python学习_01_对象

    之前关于python的知识比较零散,这一个系列的随笔将python重新学习整理一遍.学习书籍<Python核心编程>第二版. Python对象基础 python并不是一个单纯面向对象的语言 ...

  7. 关于swing的一些问题

    -问题1 :Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 & ...

  8. Nginx服务器配置之location语法分析

    location基本语法:location [=|~|~*|^~] /uri/ { - } = 严格匹配.如果这个查询匹配,那么将停止搜索并立即处理此请求. ~ 为区分大小写匹配(可用正则表达式) ! ...

  9. File System 之本地文件系统

    上一篇文章提到了,最近做一个基于 File System/IndexedDB的应用,上一篇是定额和使用的查询. 因为LocalFileSystem只有chrome支持,有点尴尬,如果按需加载又何来尴尬 ...

  10. 【Python3之字符编码】

    一.字符集和字符编码 1.定义 计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的英文.汉字等字符是二进制数转换之后的结果.通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称 ...