题目大概说给一张地图,地图每个格子都有0到9中的某一个数字。现在要在一个格子放炸弹,炸弹爆炸后水柱有两种扩展方式,一种是上、下、左、右,另一种是左上、右下、右上、左下,且四个方向的长度都一样。问放哪个格子怎么爆炸使得水柱覆盖的格子上的数字乘积最大,结果模1e9+7。

这题不会做。。

  • 首先,各个格子的值取对数,这个为了比大小,因为需要模数,通过取对数缩小值。另外也把乘法转化成加法。这是个挺经典的技巧。
  • 接下来,水柱的话肯定不能延长到0,不然功亏一篑,那么利用DP求出各个格子向8各个方向能延长多长,即dp[dir][x][y]。转移就是格子(x,y)不为0,从dp[dir][x+d[dir]][y+d[dir]]+1这儿转移,否则值为0。具体我是用记忆话搜索实现的。
  • 然后知道各个格子8个方向能延长最长长度,上、下、左、右四个方向能够延长的最小值就是第一种水柱的拓展最优的长度,而左上、右下、右上、左下四个方向的最小值就是第二种了。
  • 如何快速得出各个方向水柱覆盖的数字和——利用前缀和!这也是个挺经典的技巧。而取对数把乘法转化成加法,这就使得能利用前缀和的差求区间和。那么预处理出各个方向的前缀和就能在O(1)得出区间和了,即水柱覆盖到的格子的和。
  • 最后就是通过枚举每个格子,得到各个格子放炸弹最多能得到的数字和,更新答案。

注意最后的答案不要直接求次幂还原。。会有精度问题。。应该要记录下来,在原地图中把各个数字累乘出答案。。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<algorithm>
  5. using namespace std;
  6.  
  7. int n;
  8. double a[][];
  9. int b[][];
  10. //上、下、右、左、左上、右下、右上、左下
  11. int dx[]={-,,,,-,,-,};
  12. int dy[]={,,,-,-,,,-};
  13.  
  14. int d[][][];
  15. int dp(int dir,int x,int y){
  16. if(a[x][y]<) return d[dir][x][y]=;
  17. if(d[dir][x][y]!=-) return d[dir][x][y];
  18. int nx=x+dx[dir],ny=y+dy[dir],res=;
  19. if(nx>= && nx<=n && ny>= && ny<=n) res+=dp(dir,nx,ny);
  20. return d[dir][x][y]=res;
  21. }
  22.  
  23. double sum[][][];
  24. int rec1[][],rec2[][];
  25.  
  26. int main(){
  27. scanf("%d",&n);
  28. for(int i=; i<=n; ++i){
  29. for(int j=; j<=n; ++j){
  30. scanf("%1d",&b[i][j]);
  31. if(b[i][j]==) a[i][j]=-;
  32. else a[i][j]=log2(b[i][j]);
  33. }
  34. }
  35. for(int i=; i<=n; ++i){
  36. for(int j=; j<=n; ++j){
  37. sum[][i][j]=sum[][i][j-]+a[j][i];
  38. }
  39. }
  40. for(int i=; i<=n; ++i){
  41. for(int j=; j<=n; ++j){
  42. sum[][i][j]=sum[][i][j-]+a[i][j];
  43. }
  44. }
  45. for(int i=n; i>=; --i){
  46. int x=i,y=;
  47. for(int j=; j<=n-i+; ++j){
  48. sum[][n-i+][j]=sum[][n-i+][j-]+a[x][y];
  49. rec1[x][y]=j;
  50. ++x; ++y;
  51. }
  52. }
  53. for(int i=; i<=n; ++i){
  54. int x=,y=i;
  55. for(int j=; j<=n-i+; ++j){
  56. sum[][n+i-][j]=sum[][n+i-][j-]+a[x][y];
  57. rec1[x][y]=j;
  58. ++x; ++y;
  59. }
  60. }
  61. for(int i=; i<=n; ++i){
  62. int x=,y=i;
  63. for(int j=; j<=i; ++j){
  64. sum[][i][j]=sum[][i][j-]+a[x][y];
  65. rec2[x][y]=j;
  66. ++x; --y;
  67. }
  68. }
  69. for(int i=; i<=n; ++i){
  70. int x=i,y=n;
  71. for(int j=; j<=n-i+; ++j){
  72. sum[][n+i-][j]=sum[][n+i-][j-]+a[x][y];
  73. rec2[x][y]=j;
  74. ++x; --y;
  75. }
  76. }
  77. memset(d,-,sizeof(d));
  78. for(int k=; k<; ++k){
  79. for(int i=; i<=n; ++i){
  80. for(int j=; j<=n; ++j){
  81. dp(k,i,j);
  82. }
  83. }
  84. }
  85. double ans=-;
  86. int ansx,ansy,ansdir=-,anslen;
  87. for(int i=; i<=n; ++i){
  88. for(int j=; j<=n; ++j){
  89. if(a[i][j]<) continue;
  90.  
  91. int len=min(min(d[][i][j],d[][i][j]),min(d[][i][j],d[][i][j]));
  92. double res=;
  93. res+=sum[][j][i]-sum[][j][i-len];
  94. res+=sum[][j][i+len-]-sum[][j][i];
  95. res+=sum[][i][j-]-sum[][i][j-len];
  96. res+=sum[][i][j+len-]-sum[][i][j];
  97. if(ans<res){
  98. ans=res;
  99. ansx=i; ansy=j; ansdir=; anslen=len;
  100. }
  101.  
  102. len=min(min(d[][i][j],d[][i][j]),min(d[][i][j],d[][i][j]));
  103. res=;
  104. res+=sum[][n-i+j][rec1[i][j]]-sum[][n-i+j][rec1[i][j]-len];
  105. res+=sum[][n-i+j][rec1[i][j]+len-]-sum[][n-i+j][rec1[i][j]];
  106. res+=sum[][i+j-][rec2[i][j]-]-sum[][i+j-][rec2[i][j]-len];
  107. res+=sum[][i+j-][rec2[i][j]+len-]-sum[][i+j-][rec2[i][j]];
  108. if(ans<res){
  109. ans=res;
  110. ansx=i; ansy=j; ansdir=; anslen=len;
  111. }
  112. }
  113. }
  114. if(ansdir==-){
  115. printf("");
  116. return ;
  117. }
  118. long long res=;
  119. if(ansdir==){
  120. for(int i=ansx-anslen+; i<=ansx+anslen-; ++i){
  121. res*=b[i][ansy];
  122. res%=;
  123. }
  124. for(int i=ansy-anslen+; i<=ansy+anslen-; ++i){
  125. if(i==ansy) continue;
  126. res*=b[ansx][i];
  127. res%=;
  128. }
  129. }else{
  130. int x=ansx-anslen+,y=ansy-anslen+;
  131. for(int i=; i<anslen*; ++i){
  132. res*=b[x][y];
  133. res%=;
  134. ++x; ++y;
  135. }
  136. x=ansx-anslen+; y=ansy+anslen-;
  137. for(int i=; i<anslen*; ++i){
  138. if(x==ansx && y==ansy){
  139. ++x; --y;
  140. continue;
  141. }
  142. res*=b[x][y];
  143. res%=;
  144. ++x; --y;
  145. }
  146. }
  147. printf("%lld",res);
  148. return ;
  149. }

Codeforces 677E Vanya and Balloons(DP + 一些技巧)的更多相关文章

  1. Codeforces 677E Vanya and Balloons

    Vanya and Balloons 枚举中心去更新答案, 数字过大用log去比较, 斜着的旋转一下坐标, 然后我旋出来好多bug.... #include<bits/stdc++.h> ...

  2. Codeforces 677D - Vanya and Treasure - [DP+优先队列BFS]

    题目链接:http://codeforces.com/problemset/problem/677/D 题意: 有 $n \times m$ 的网格,每个网格上有一个棋子,棋子种类为 $t[i][j] ...

  3. Codeforces 677D Vanya and Treasure 暴力+BFS

    链接 Codeforces 677D Vanya and Treasure 题意 n*m中有p个type,经过了任意一个 type=i 的各自才能打开 type=i+1 的钥匙,最初有type=1的钥 ...

  4. codeforces 492E. Vanya and Field(exgcd求逆元)

    题目链接:codeforces 492e vanya and field 留个扩展gcd求逆元的板子. 设i,j为每颗苹果树的位置,因为gcd(n,dx) = 1,gcd(n,dy) = 1,所以当走 ...

  5. [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)

    [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数. 让你求出1到m中所有权 ...

  6. Codeforces Round #355 (Div. 2) D. Vanya and Treasure dp+分块

    题目链接: http://codeforces.com/contest/677/problem/D 题意: 让你求最短的从start->...->1->...->2->. ...

  7. Codeforces 900 E. Maximum Questions (DP,技巧)

    题目链接:900 E. Maximum Questions 题意: 给出一个长度为n只含有a和b还有'?'的串s,且'?'可以被任意替换为a或b.再给出一个字符串t (奇数位上为a,偶数位上为b,所以 ...

  8. E. Vanya and Balloons Codeforces Round #355 (Div. 2)

    http://codeforces.com/contest/677/problem/E 题意:有n*n矩形,每个格子有一个值(0.1.2.3),你可以在矩形里画一个十字(‘+’形或‘x’形),十字的四 ...

  9. codeforces 721C (拓排 + DP)

    题目链接:http://codeforces.com/contest/721/problem/C 题意:从1走到n,问在时间T内最多经过多少个点,按路径顺序输出. 思路:比赛的时候只想到拓排然后就不知 ...

随机推荐

  1. oracle 的PACKAGE恢复过程

    SELECT obj# FROM obj$ AS OF TIMESTAMP TO_TIMESTAMP('2016-06-30', 'YYYY-MM-DD') WHERE NAME = 'PFWZ_AP ...

  2. linux下U盘文件只读的解决办法

    . 在终端运行如下命令 tail -f /var/log/syslog . 插入有只读文件系统故障的U盘 . 观察命令行输出 输出局部如下: Jul :: cslouis-pc kernel: [15 ...

  3. 手工加载DLL

    1.为了能找到dll的函数地址,生成dll时需要将其中的函数声明为C函数(extern "C"): #ifndef __MYDLL_H#define __MYDLL_H #ifde ...

  4. Java——Cookie与Session

    Cookie通过客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份. 1.Cookie  1.1概念及使用方法 Cookie实际上是一小段文本信息.客户端请求服务器,如果服务 ...

  5. Linux获取当前用户信息函数

    转自:http://net.pku.edu.cn/~yhf/linux_c/function/07.html endgrent(关闭组文件) 相关函数 getgrent,setgrent 表头文件 # ...

  6. 【Python】 用python实现定时数据解析服务(前言)

    一.Why do it? 背景:项目里上传上来的数据都是未解析的数据,而且数据量还算挺庞大的,每天上传的数据有5kw左右,如果用数据库自带的作业来解析的话,数据库会造成严重的阻塞.因此打算把数据读到外 ...

  7. Delphi中exit、break、continue等跳出操作的区别

    Delphi中表示跳出的有break,continue,abort,exit,halt,runerror等 1.break 强制退出最近的一层循环(注意:只能放在循环里:而且是只能跳出最近的一层循环) ...

  8. tornado web高级开发项目之抽屉官网的页面登陆验证、form验证、点赞、评论、文章分页处理、发送邮箱验证码、登陆验证码、注册、发布文章、上传图片

    本博文将一步步带领你实现抽屉官网的各种功能:包括登陆.注册.发送邮箱验证码.登陆验证码.页面登陆验证.发布文章.上传图片.form验证.点赞.评论.文章分页处理以及基于tornado的后端和ajax的 ...

  9. 攻城狮在路上(叁)Linux(十五)--- 文件与目录的默认权限与隐藏权限

    一.文件默认权限:umask <==需要被减去的权限. 1.umask指的是当前用户在新建文件或者目录时的默认权限,如0022; 2.默认情况下,用户创建文件的最大权限为666; 创建目录的最大 ...

  10. Datagard產生gap

    本文轉載自無雙的小寶的博客:http://www.cnblogs.com/sopost/archive/2010/09/11/2190085.html 有時候因為網路或備份故障等原因,主機所產生的歸檔 ...