1.Game

【题目描述】

明明和亮亮在玩一个游戏。桌面上一行有n个格子,一些格子中放着棋子。明明和亮亮轮流选择如下方式中的一种移动棋子(图示中o表示棋子,*表示空着的格子):

1) 当一枚棋子的右边是空格子的话,可以将这枚棋子像右移动一格。

**o***         ->           ***o**

2) 当一枚棋子的右边连续两个都有棋子,并且这个棋子往右边数第3格没有棋子,那么可以将这个棋子可以跳过去那两个棋子

**ooo*        ->           ***oo*

当任何一枚棋子到达最右边的格子时,这枚棋子自动消失。当一方不能移动时,这方输。假设明明和亮亮都采取最优策略,明明先走,谁将取胜?

【输入数据】

第一行一个整数T表示数据组数, 0 < T < 10。

之后T组数据,每组两行,第一行n 表示格子个数,第二行n个字符表示每个格子的情况,o表示有棋子,*表示空着。

【输出数据】

对于每组数据一个输出,M表示明明赢,L表示亮亮赢。

【样例输入】

4

2

*o

5

*o***

6

**o**o

14

*o***ooo**oo**

【样例输出】

L

M

M

L

【数据范围】

0 <T < 10

对于50%的数据, n < 20。

对于100%的数据, n < 1000。


第一题就博弈。。跪跪跪。。

真心不会博弈。。今晚好好重学一遍。。

看题解好像很好理解???


Game解题报告

对于前50%的数据,由于n<20,整个棋盘的状态个数 < 2^20。 由于状态数有限,我们可以采取记忆化搜索的办法来实现。

但对于100%的数据,n的最大可能值达到999,记忆化搜索就不怎么可行了。其实本题有一个更简单的做法:

考虑每个棋子到最右边格子的距离。把所有棋子这样的距离的总和计为s。我们发现不管选择两种操作中的一种操作,每走一步,s的奇偶性都会发生一次变化。所以说,如果第一次轮到明明时,s是奇数,那么每次轮到明明时s都是奇数。而当s是奇数时,s肯定>0,这时明明总可以走最右边的棋子。也就是说当s为奇数时,总有棋子可以走。所以说,一开始若s为奇数,则明明必胜。同理,若一开始s为偶数,则当亮亮走的时候s总是奇数,所以明明必败。


贴个代码:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. using namespace std;
  6.  
  7. const int N=,M=<<;
  8. int n,f[][M],a[N],b[N];
  9. char c[N],cc[N];
  10.  
  11. int dfs(int x,int s)
  12. {
  13. if((s&)!=) s--;
  14. if(f[x][s]!=-) return f[x][s];
  15. int ss,ans=;
  16. for(int i=;i<n;i++)
  17. {
  18. if((s&(<<i))!= && (i->= && (s&(<<(i-)))==))
  19. {
  20. ss=s-(<<i)+(<<(i-));
  21. if(dfs(-x,ss)==) ans=;
  22. }
  23. if((s&(<<i))!= && (i->= && (s&(<<(i-)))!=) && (i->= && (s&(<<(i-)))!=) && (i->= && (s&(<<(i-)))==))
  24. {
  25. ss=s-(<<i)+(<<(i-));
  26. if(dfs(-x,ss)==) ans=;
  27. }
  28. }
  29. f[x][s]=ans;
  30. // printf("f %d %d = %d\n",x,s,ans);
  31. return ans;
  32. }
  33.  
  34. void solve1()
  35. {
  36. scanf("%s",c);
  37. memset(f,-,sizeof(f));
  38. f[][]=f[][]=;
  39. int x=;
  40. for(int i=;i<n;i++)
  41. {
  42. if(c[i]=='o') x|=(<<(n--i));
  43. }
  44. // printf("x = %d\n",x);
  45. if(dfs(,x)==) printf("M\n");
  46. else printf("L\n");
  47. }
  48.  
  49. void solve2()
  50. {
  51. scanf("%s",c+);
  52. int sum=;
  53. for(int i=;i<=n;i++)
  54. {
  55. if(c[i]=='o') sum+=n-i;
  56. }
  57. if(sum%==) printf("L\n");
  58. else printf("M\n");
  59. }
  60.  
  61. int main()
  62. {
  63. // freopen("a.in","r",stdin);
  64. freopen("game.in","r",stdin);
  65. freopen("game.out","w",stdout);
  66. int T,x;
  67. scanf("%d",&T);
  68. while(T--)
  69. {
  70. scanf("%d",&n);
  71. if(n<=) solve1();
  72. else solve2();
  73. }
  74. return ;
  75. }

2.Walk

【题目描述】

有一块n *n 的土地上,明明和亮亮站在(1,1)处。每块地上写有一个数字a(i, j)。现在他们决定玩一个游戏,每一秒钟,他们俩走向相邻且坐标变大的格子(从(x,y)到(x+1,y)或者从(x,y)到(x,y+1)),他们俩可以按照不同方式来走,最后经过2n-1步到达(n,n)处。明明和亮亮每一秒钟计算他们站的两个位置上数字的差的绝对值,他们希望这些差值的和最大,请问这个最大的和是多少?

【输入数据】

第一行一个正整数n。

后面n行,每行n个整数,分别表示每块地上的数字。

【输出数据】

一个整数,表示最大的差值的和。

【样例输入】

4

1 2 3 4

1 5 3 2

8 1 3 4

3 2 1 5

【样例输出】

13

【数据范围】

n <= 100, 每块地上的数字的绝对值不超过300。


没什么好说的。就直接dp,f[i][j][k]表示走了i步,第一个人的横坐标是j,第二个人的横坐标是k。

通过走了i步可以算出纵坐标。

第一维只开了100又跪了。。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. using namespace std;
  6.  
  7. const int N=;
  8. int n,a[N][N],f[N][N][N];
  9. int dx[]={,};
  10. int dy[]={,};
  11.  
  12. int myabs(int x){return x> ? x:-x;}
  13. int minn(int x,int y){return x<y ? x:y;}
  14. int maxx(int x,int y){return x>y ? x:y;}
  15.  
  16. int main()
  17. {
  18. // freopen("a.in","r",stdin);
  19. freopen("walk.in","r",stdin);
  20. freopen("walk.out","w",stdout);
  21. scanf("%d",&n);
  22. for(int i=;i<n;i++)
  23. for(int j=;j<n;j++)
  24. scanf("%d",&a[i][j]);
  25. memset(f,-,sizeof(f));
  26. f[][][]=;
  27. int x1,y1,x2,y2,xx1,yy1,xx2,yy2;
  28. for(int i=;i<=*n-;i++)
  29. for(int j=;j<n;j++)
  30. for(int k=;k<n;k++)
  31. {
  32. if(f[i][j][k]==-) continue;
  33. // printf("f %d %d %d = %d\n",i,j,k,f[i][j][k]);
  34. x1=j;y1=i-j;
  35. x2=k;y2=i-k;
  36. for(int ii=;ii<=;ii++)
  37. for(int jj=;jj<=;jj++)
  38. {
  39. xx1=x1+dx[ii];yy1=y1+dy[ii];
  40. xx2=x2+dx[jj];yy2=y2+dy[jj];
  41. if(xx1>=n || yy1>=n || xx2>=n || yy2>=n) continue;
  42. f[i+][xx1][xx2]=maxx(f[i+][xx1][xx2],f[i][x1][x2]+myabs(a[xx1][yy1]-a[xx2][yy2]));
  43. }
  44. }
  45. printf("%d\n",f[*n-][n-][n-]);
  46. return ;
  47. }

3. Trip

【题目描述】

小朋友们出去郊游,明明和亮亮负责在草地上开一个篝火晚会。这个草地你可以认为是又 N * M 块单位长度为1的小正方形的草组成。

显然有的地方草长的好,有的地方长的不好,坐在上面显然舒服度是不一样的,于是每一块草都有一个舒服度 F。

现在明明和亮亮要选定一个 a*b 的草场作为晚会的地点,小朋友们就坐在上面,显然他希望小朋友们坐的最舒服!

不过别急,篝火晚会怎么能少了篝火呢,篝火需要占用 c*d 的草地,当然,篝火必须严格放置在选定的草地的内部,也就是说,篝火的边界不能和选定操场的边界有公共部分,不然学生们怎么围着篝火开晚会呢?

给定 N*M 大草地每一块的舒服度,寻找一个 a*b 的草地,除去一个严格内部的 c*d 的子草地,使得总的舒服度最大。

【输入数据】

第1行:6个整数,M ,  N,  b,   a,   d,   c

第2~N+1行:每行 M 个整数,第 i行j列的整数 Fi,j 表示,第 i行j列的单位草地的舒服度。

【输出数据】

一个整数,表示最大的舒服值。

【样例输入】

8 5 5 3 2 1

1 5 10 3 7 1 2 5

6 12 4 4 3 3 1 5

2 4 3 1 6 6 19 8

1 1 1 3 4 2 4 5

6 6 3 3 3 2 2 2

【样例输出】

70

【数据说明】

下面的图片就是对样例的解释,阴影区域就是最佳的选择方案。

比如方案 4 1 4 1 就是显然非法的,因为篝火出现出现在了选定草地的边界,学生们无法严格围住篝火。

【数据范围】

1 ≤ Fi,j ≤ 100

3 ≤ a ≤ N

3 ≤ b ≤ M

1 ≤ c ≤ a-2

1 ≤ d ≤ b-2

对于 40% 的数据 N,M ≤ 10

对于 60% 的数据 N,M ≤ 150

对于 100% 的数据 N,M ≤ 1000


这题其实就是求一个矩阵里的最小值。

然后就可以行做一遍,列做一遍。

我们可以一行一行的求出每个连续b-d-1个c*d矩形的最小值。再基于这个最小值,一列一列的求出每个a*b大矩形中和最小的c*d矩形。这样我们就可以找到最优的舒服值了。本算法的时间复杂度是O(MN)。

原本用优先队列。。然后超时了4个点哭。。

然后用单调队列就巨快了。。orz。。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<vector>
  6. #include<queue>
  7. using namespace std;
  8.  
  9. const int N=;
  10. int n,m,A,B,C,D;
  11. int a[N][N],c[N][N],s[N][N],t[N][N],p[N][N],rr[N][N],R[N][N];
  12. struct node{int x,d;}q[N*N];
  13.  
  14. int maxx(int x,int y){return x>y ? x:y;}
  15.  
  16. void solve()
  17. {
  18. node k;
  19. int ind,l,r;
  20. for(int i=;i<=n;i++)
  21. {
  22. l=;r=;
  23. for(int j=;j+D-<=B-;j++)
  24. {
  25. k.x=j;k.d=p[i][j];
  26. while(q[r].d>k.d && l<=r) r--;
  27. q[++r]=k;
  28. ind=j;
  29. }
  30. for(int j=;j+B-<=m;j++)
  31. {
  32. while(q[l].x<j) l++;
  33. rr[i][j]=q[l].d;
  34. ind++;k.x=ind;k.d=p[i][ind];
  35. while(q[r].d>k.d && l<=r) r--;
  36. q[++r]=k;
  37. }
  38. }
  39. for(int i=;i<=m;i++)
  40. {
  41. l=;r=;
  42. for(int j=;j+C-<=A-;j++)
  43. {
  44. k.x=j;k.d=rr[j][i];
  45. while(q[r].d>k.d && l<=r) r--;
  46. q[++r]=k;
  47. ind=j;
  48. }
  49. for(int j=;j+A-<=n;j++)
  50. {
  51. while(q[l].x<j) l++;
  52. R[j][i]=q[l].d;
  53. ind++;k.x=ind;k.d=rr[ind][i];
  54. while(q[r].d>k.d && l<=r) r--;
  55. q[++r]=k;
  56. }
  57. }
  58. int ans=;
  59. for(int i=;i+A-<=n;i++)
  60. for(int j=;j+B-<=m;j++)
  61. ans=maxx(ans,t[i][j]-R[i+][j+]);
  62. printf("%d\n",ans);
  63. }
  64.  
  65. int main()
  66. {
  67. // freopen("a.in","r",stdin);
  68. freopen("trip.in","r",stdin);
  69. freopen("trip.out","w",stdout);
  70. scanf("%d%d%d%d%d%d",&m,&n,&B,&A,&D,&C);
  71. for(int i=;i<=n;i++)
  72. for(int j=;j<=m;j++)
  73. scanf("%d",&a[i][j]);
  74. memset(s,,sizeof(s));
  75. for(int i=;i<=n;i++)
  76. for(int j=;j<=m;j++)
  77. {
  78. s[i][j]=s[i-][j]+s[i][j-]-s[i-][j-]+a[i][j];
  79. }
  80. for(int i=;i+A-<=n;i++)
  81. for(int j=;j+B-<=m;j++)
  82. t[i][j]=s[i+A-][j+B-]-s[i+A-][j-]-s[i-][j+B-]+s[i-][j-];
  83. for(int i=;i+C-<=n;i++)
  84. for(int j=;j+D-<=m;j++)
  85. p[i][j]=s[i+C-][j+D-]-s[i+C-][j-]-s[i-][j+D-]+s[i-][j-];
  86. solve();
  87. return ;
  88. }

点分治裸题。。

先找出树的重心,对于每个点维护一个到树的重心的乘积d[x]。

然后找经过树的重心的树链是否有乘积为k的。

然后分治算各个子树。

ps:学了奥爷爷的线性求逆元。。强啊。。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<vector>
  6. #include<queue>
  7. using namespace std;
  8.  
  9. typedef long long LL;
  10. const int N=,M=,mod=,INF=(int)1e9;
  11. int n,len,sl,tl,a1,a2;
  12. LL K,d[N],val[N],t[N],s[N],v[M],ny[M];
  13. int first[N],size[N],mark[N],id[M];
  14. struct node{
  15. int x,y,next;
  16. }a[*N];
  17.  
  18. int minn(int x,int y){return x<y ? x:y;}
  19.  
  20. LL quickpow(LL x,LL y)
  21. {
  22. LL ans=;
  23. while(y)
  24. {
  25. if(y&) ans=ans*x%mod;
  26. x=x*x%mod;
  27. y/=;
  28. }
  29. return ans;
  30. }
  31.  
  32. int ins(int x,int y)
  33. {
  34. a[++len].x=x;a[len].y=y;
  35. a[len].next=first[x];first[x]=len;
  36. }
  37.  
  38. void find_root(int x,int fa,int tot,int &root)
  39. {
  40. size[x]=;
  41. bool bk=;
  42. for(int i=first[x];i;i=a[i].next)
  43. {
  44. int y=a[i].y;
  45. if(mark[y] || y==fa) continue;
  46. find_root(y,x,tot,root);
  47. size[x]+=size[y];
  48. if(*size[y]>tot) bk=;
  49. }
  50. if(bk && *(tot-size[x])<=tot) root=x;
  51. }
  52.  
  53. void DFS(int x,int fa,int root)
  54. {
  55. d[x]=d[fa]*val[x]%mod;
  56. t[++tl]=d[x];id[tl]=x;
  57. LL now=(ny[d[x]]*K%mod)*val[root]%mod;
  58. if(v[now])
  59. {
  60. int X=x,Y=v[now];
  61. if(X>Y) swap(X,Y);
  62. if(X<a1) a1=X,a2=Y;
  63. else if(X==a1 && Y<a2) a2=Y;
  64. }
  65. size[x]=;
  66. for(int i=first[x];i;i=a[i].next)
  67. {
  68. int y=a[i].y;
  69. if(mark[y] || y==fa) continue;
  70. DFS(y,x,root);
  71. size[x]+=size[y];
  72. }
  73. }
  74.  
  75. int dfs(int x,int tot)
  76. {
  77. find_root(x,,tot,x);
  78. // printf("tot = %d root = %d\n",tot,x);
  79. mark[x]=;
  80. sl=;s[++sl]=val[x];
  81. d[x]=val[x];
  82. for(int i=first[x];i;i=a[i].next)
  83. {
  84. int y=a[i].y;
  85. if(mark[y]==) continue;
  86. tl=;
  87. DFS(y,x,x);
  88. for(int j=;j<=tl;j++)
  89. {
  90. s[++sl]=t[j];
  91. if(v[t[j]]==) v[t[j]]=id[j];
  92. else v[t[j]]=minn(v[t[j]],id[j]);
  93. }
  94. }
  95. if(v[K])
  96. {
  97. int X=x,Y=v[K];
  98. if(X>Y) swap(X,Y);
  99. if(X<a1) a1=X,a2=Y;
  100. else if(X==a1 && Y<a2) a2=Y;
  101. }
  102. for(int i=;i<=sl;i++) v[s[i]]=;
  103. for(int i=first[x];i;i=a[i].next)
  104. {
  105. int y=a[i].y;
  106. if(mark[y]==) continue;
  107. dfs(y,size[y]);
  108. }
  109. }
  110.  
  111. int main()
  112. {
  113. // freopen("a.in","r",stdin);
  114. freopen("multik.in","r",stdin);
  115. freopen("multik.out","w",stdout);
  116. scanf("%d%d",&n,&K);
  117. len=;a1=INF;a2=INF;
  118. memset(v,,sizeof(v));
  119. memset(mark,,sizeof(mark));
  120. memset(first,,sizeof(first));
  121. ny[]=;
  122. for(int i=;i<=mod;i++)
  123. ny[i]=(mod-(mod/i))*ny[mod%i]%mod;
  124. // ny[i]=quickpow(i,mod-2);
  125. for(int i=;i<=n;i++)
  126. scanf("%d",&val[i]);
  127. for(int i=;i<n;i++)
  128. {
  129. int x,y;
  130. scanf("%d%d",&x,&y);
  131. ins(x,y);
  132. ins(y,x);
  133. }
  134. dfs(,n);
  135. if(a1<INF) printf("%d %d\n",a1,a2);
  136. else printf("No solution\n");
  137. return ;
  138. }

【20161109】noip模拟赛的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  10. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

随机推荐

  1. 有关c#的学习笔记整理与心得

    [ 塔 · 第 一 条 约 定 ] 整理c#:Array Arraylist List Hashtable Dictionary Stack Queue等 Array 的容量是固定的,而 ArrayL ...

  2. 总结get和post区别

    参考博文: 浅谈HTTP中Get与Post的区别 1. 数据传递方向: Get是向服务器发索取数据的一种请求,Post是向服务器提交数据的一种请求 (都是请求,并不是一个取一个发) Get:①用于获取 ...

  3. ACM 第十一天

    多校7题目 GuGuFishtion Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  4. lintcode-182-删除数字

    182-删除数字 给出一个字符串 A, 表示一个 n 位正整数, 删除其中 k 位数字, 使得剩余的数字仍然按照原来的顺序排列产生一个新的正整数. 找到删除 k 个数字之后的最小正整数. N < ...

  5. 【Linux】- ps -ef |grep 命令

    ps:将某个进程显示出来 grep:查找 |:管道命令 表示ps命令与grep同时执行 PS是LINUX下最常用的也是非常强大的进程查看命令 grep命令是查找,是一种强大的文本搜索工具,它能使用正则 ...

  6. c#中语句的先后顺序对结果的影响

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test ...

  7. sql sever 数据表

    对视图进行操作,要在第三块区域进行添加记录操作,回车,然后会同步到所有相关数据表中. 记录不是列,而是行,不要混淆. 第二块区域是各个属性,就是说明: 第一块区域是要进行显示的字段,选中什么 显示什么 ...

  8. Spring Boot 最简单的HelloWorld

    创建一个Spring Boot,可以直接使用构建工具(Maven或Gradle)创建,也可以使用spring.io网站创建,一般会选择使用spring.io创建 使用IDEA创建一个Spring Bo ...

  9. 使用mac电脑,对Github客户端的简单操作1----开源项目

    工作之余自己也会一写一些小的程序项目,由于一直没时间“折腾”开源,之前写博客都是直接粘代码片段,今天看别人写技术博客大都会放出项目Github地址,突然感觉自己有点点out and low,作为一个励 ...

  10. git log 查看提交记录

    git log 查看提交记录 1. git log 查看提交历史记录2. git log --oneline 或者 git log --pretty=oneline 以精简模式显示3. git log ...