zoukankan      html  css  js  c++  java
  • Codeforces 677E Vanya and Balloons(DP + 一些技巧)

    题目大概说给一张地图,地图每个格子都有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[1111][1111];
      9 int b[1111][1111];
     10 //上、下、右、左、左上、右下、右上、左下
     11 int dx[]={-1,1,0,0,-1,1,-1,1};
     12 int dy[]={0,0,1,-1,-1,1,1,-1};
     13 
     14 int d[8][1111][1111];
     15 int dp(int dir,int x,int y){
     16     if(a[x][y]<0) return d[dir][x][y]=0;
     17     if(d[dir][x][y]!=-1) return d[dir][x][y];
     18     int nx=x+dx[dir],ny=y+dy[dir],res=1;
     19     if(nx>=1 && nx<=n && ny>=1 && ny<=n) res+=dp(dir,nx,ny);
     20     return d[dir][x][y]=res;
     21 }
     22 
     23 double sum[4][2222][1111];
     24 int rec1[1111][1111],rec2[1111][1111];
     25 
     26 int main(){
     27     scanf("%d",&n);
     28     for(int i=1; i<=n; ++i){
     29         for(int j=1; j<=n; ++j){
     30             scanf("%1d",&b[i][j]);
     31             if(b[i][j]==0) a[i][j]=-1;
     32             else a[i][j]=log2(b[i][j]);
     33         }
     34     }
     35     for(int i=1; i<=n; ++i){
     36         for(int j=1; j<=n; ++j){
     37             sum[0][i][j]=sum[0][i][j-1]+a[j][i];
     38         }
     39     }
     40     for(int i=1; i<=n; ++i){
     41         for(int j=1; j<=n; ++j){
     42             sum[1][i][j]=sum[1][i][j-1]+a[i][j];
     43         }
     44     }
     45     for(int i=n; i>=1; --i){
     46         int x=i,y=1;
     47         for(int j=1; j<=n-i+1; ++j){
     48             sum[2][n-i+1][j]=sum[2][n-i+1][j-1]+a[x][y];
     49             rec1[x][y]=j;
     50             ++x; ++y;
     51         }
     52     }
     53     for(int i=2; i<=n; ++i){
     54         int x=1,y=i;
     55         for(int j=1; j<=n-i+1; ++j){
     56             sum[2][n+i-1][j]=sum[2][n+i-1][j-1]+a[x][y];
     57             rec1[x][y]=j;
     58             ++x; ++y;
     59         }
     60     }
     61     for(int i=1; i<=n; ++i){
     62         int x=1,y=i;
     63         for(int j=1; j<=i; ++j){
     64             sum[3][i][j]=sum[3][i][j-1]+a[x][y];
     65             rec2[x][y]=j;
     66             ++x; --y;
     67         }
     68     }
     69     for(int i=2; i<=n; ++i){
     70         int x=i,y=n;
     71         for(int j=1; j<=n-i+1; ++j){
     72             sum[3][n+i-1][j]=sum[3][n+i-1][j-1]+a[x][y];
     73             rec2[x][y]=j;
     74             ++x; --y;
     75         }
     76     }
     77     memset(d,-1,sizeof(d));
     78     for(int k=0; k<8; ++k){
     79         for(int i=1; i<=n; ++i){
     80             for(int j=1; j<=n; ++j){
     81                 dp(k,i,j);
     82             }
     83         }
     84     }
     85     double ans=-1;
     86     int ansx,ansy,ansdir=-1,anslen;
     87     for(int i=1; i<=n; ++i){
     88         for(int j=1; j<=n; ++j){
     89             if(a[i][j]<0) continue;
     90 
     91             int len=min(min(d[0][i][j],d[1][i][j]),min(d[2][i][j],d[3][i][j]));
     92             double res=0;
     93             res+=sum[0][j][i]-sum[0][j][i-len];
     94             res+=sum[0][j][i+len-1]-sum[0][j][i];
     95             res+=sum[1][i][j-1]-sum[1][i][j-len];
     96             res+=sum[1][i][j+len-1]-sum[1][i][j];
     97             if(ans<res){
     98                 ans=res;
     99                 ansx=i; ansy=j; ansdir=0; anslen=len;
    100             }
    101 
    102             len=min(min(d[4][i][j],d[5][i][j]),min(d[6][i][j],d[7][i][j]));
    103             res=0;
    104             res+=sum[2][n-i+j][rec1[i][j]]-sum[2][n-i+j][rec1[i][j]-len];
    105             res+=sum[2][n-i+j][rec1[i][j]+len-1]-sum[2][n-i+j][rec1[i][j]];
    106             res+=sum[3][i+j-1][rec2[i][j]-1]-sum[3][i+j-1][rec2[i][j]-len];
    107             res+=sum[3][i+j-1][rec2[i][j]+len-1]-sum[3][i+j-1][rec2[i][j]];
    108             if(ans<res){
    109                 ans=res;
    110                 ansx=i; ansy=j; ansdir=1; anslen=len;
    111             }
    112         }
    113     }
    114     if(ansdir==-1){
    115         printf("0");
    116         return 0;
    117     }
    118     long long res=1;
    119     if(ansdir==0){
    120         for(int i=ansx-anslen+1; i<=ansx+anslen-1; ++i){
    121             res*=b[i][ansy];
    122             res%=1000000007;
    123         }
    124         for(int i=ansy-anslen+1; i<=ansy+anslen-1; ++i){
    125             if(i==ansy) continue;
    126             res*=b[ansx][i];
    127             res%=1000000007;
    128         }
    129     }else{
    130         int x=ansx-anslen+1,y=ansy-anslen+1;
    131         for(int i=1; i<anslen*2; ++i){
    132             res*=b[x][y];
    133             res%=1000000007;
    134             ++x; ++y;
    135         }
    136         x=ansx-anslen+1; y=ansy+anslen-1;
    137         for(int i=1; i<anslen*2; ++i){
    138             if(x==ansx && y==ansy){
    139                 ++x; --y;
    140                 continue;
    141             }
    142             res*=b[x][y];
    143             res%=1000000007;
    144             ++x; --y;
    145         }
    146     }
    147     printf("%lld",res);
    148     return 0;
    149 }
  • 相关阅读:
    C# 特性学习笔记
    Nhibernate学习的第二天
    Nhibernate学习的第一天
    SQL循环添加表中的字段
    加班
    bat文件重启SQL服务和IIS服务
    判断是不是手机访问的网站
    解决Ueditor 不兼容IE7 和IE8
    实现链表的初始化,按值查找,插入,删除
    判断任一二叉树,是否为满二叉树.(输出二叉树,节点总数,二叉树深度)
  • 原文地址:https://www.cnblogs.com/WABoss/p/5669524.html
Copyright © 2011-2022 走看看