• codeforces 463C. Gargari and Bishops 解题报告


    题目链接:http://codeforces.com/contest/463/problem/C

    题目意思:要在一个 n * n 大小的棋盘上放置两个bishop,bishop可以攻击的所有位置是包括经过bishop 位置的两条成90度的对角线所经过的所有坐标点。每个坐标点都有数字在上面,放置一个bishop后,可以获得能被放置的bishop攻击的所有坐标点的数字的和。但是有一个条件限制:同一个坐标点不能被两个bishop攻击,也就是四条对角线的交点不能是棋盘上的某个坐标点。求出在该条件限制下,两个bishop的放置位置以及能获得的最大和。

         首先没有看到这个条件wa了很多次: place two bishops on the chessboard in such a way that there is no cell that is attacked by both of them。

         好不容易看到之后,就各种TLE了,原来是读入问题!!!!涨姿势勒= =

         可喜的是,原来自己最开始的做法是可取的,不过都是因为读入问题。

         先介绍作者的灵活高效版:

         先看一个图:

       

         

         作者的做法有两个巧妙之处:

         (1)求 bishop 能够攻击的所有坐标点的和,简而言之就是一个坐标点的两条对角线的和。

      设两个数组d1[],d2[],用于保存两种方向下的对角线总和。(虚线部分标明了方向)。d1[]数组是通过d1[i+j] += board[i][j] 来算的,而 d2是这样:d2[i-j+n] += board[i][j]。

          如果要求某个特定的坐标(i, j)的对角线和,那么就是d1[i+j] + d2[i-j+n] - board[i][j] ,之所以要减去board是因为每个坐标点的和都被重复算多了一次。

         (2)判断攻击的方法

         假设 bishop1 坐标为(i1, j1),bishop2 为(i2, j2),如果( i1 + j1),( i2 + j2) 同奇或同偶,那么就存在某一个坐标点同时被两个bishop 攻击!

         所以要满足不存在某个坐标同时被两个bishop 攻击,就需要(i1 + j1) 和 (i2+j2) 处于一奇一偶的情况。那么奇数找一个最大值,偶数的话又找一个最大值,加起来就是两个bishop放置后能够获得的最大和了。

              Time:  217ms     Memory:  31400KB

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 typedef long long LL;
     8 const int maxn = 2000 + 2;
     9 
    10 LL board[maxn][maxn];
    11 LL d1[maxn<<1], d2[maxn<<1];
    12 pair<int, int> ans[2];
    13 LL tmp[2];
    14 
    15 inline LL read()   // 这个读入是避免TLE的关键
    16 {
    17     int x = 0, f = 1;
    18     char ch = getchar();
    19     while (ch >= '0' && ch <= '9')
    20     {
    21         x = 10*x + ch-'0';
    22         ch = getchar();
    23     }
    24     return (LL)(x * f);
    25 }
    26 
    27 int main()
    28 {
    29     int n, x1, x2, y1, y2;
    30     while (scanf("%d", &n) != EOF)
    31     {
    32         memset(d1, 0, sizeof(d1));
    33         memset(d2, 0, sizeof(d2));
    34         getchar();   // 不能省!n之后有个空格= =
    35         for (int i = 1; i <= n; i++)
    36         {
    37             for (int j = 1; j <= n; j++)
    38             {
    39                  board[i][j] = read();
    40                  d1[i+j] += board[i][j];
    41                  d2[i-j+n] += board[i][j];
    42             }
    43         }
    44         tmp[0] = tmp[1] = -1;    // 0也可以,但是后面要>=,防止多次被替换还是-1好,省时一点吧
    45         for (int i = 1; i <= n; i++)
    46         {
    47             for (int j = 1; j <= n; j++)
    48             {
    49                 LL val = d1[i+j] + d2[i-j+n] - board[i][j];
    50                 if (val > tmp[(i+j)&1])
    51                 {
    52                     tmp[(i+j)&1] = val;
    53                     ans[(i+j)&1].first = i;
    54                     ans[(i+j)&1].second = j;
    55                 }
    56             }
    57         }
    58         printf("%lld
    ", tmp[0] + tmp[1]);
    59         printf("%d %d %d %d
    ", ans[0].first, ans[0].second, ans[1].first, ans[1].second);
    60     }
    61     return 0;
    62 }
    View Code

        

         接下来就是我的做法(大家可以忽略)

         求对角线的和的时候,我是采取从第1行,第1列,最后1列出发来求得的,最后还是需要减去board[i][j],代码量好大,因为太多重复 = =

         至于判断攻击,除了利用abs函数(恰好对角线),还利用了之前做的一条 cf370A 的 Rook, Bishop  and King的做法啦—— 判断Bishop 步数。

         毕竟自己写的,留下纪念吧 = =

         真是又长又耗时啊~~ 

         Time:  1122ms     Memory:  125504KB

        

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cmath>
      6 #include <algorithm>
      7 using namespace std;
      8 
      9 typedef long long LL;
     10 const int maxn = 2000 + 2;
     11 
     12 struct node
     13 {
     14     LL s;
     15     int x, y;
     16     bool operator < (const node& a) const
     17     {
     18         return s < a.s;
     19     }
     20 }num[maxn*maxn];
     21 
     22 LL board[maxn][maxn];
     23 LL sum[maxn][maxn];
     24 
     25 inline LL read()   // 这个读入是避免TLE的关键
     26 {
     27     int x = 0, f = 1;
     28     char ch = getchar();
     29     while (ch >= '0' && ch <= '9')
     30     {
     31         x = 10*x + ch-'0';
     32         ch = getchar();
     33     }
     34     return (LL)(x * f);
     35 }
     36 
     37 int main()
     38 {
     39     int n;
     40     while (scanf("%d", &n) != EOF)
     41     {
     42         getchar();
     43         for (int i = 1; i <= n; i++)
     44         {
     45             for (int j = 1; j <= n; j++)
     46                 board[i][j] = (LL)read();
     47         }
     48         memset(sum, 0, sizeof(sum));
     49         // 第 1 行
     50         int i = 1;
     51         for (int j = 1; j <= n; j++)
     52         {
     53             LL ss = 0;
     54             int ti = i;
     55             int tj = j;   // 右下
     56             while (ti <= n && tj <= n)
     57             {
     58                 ss += board[ti][tj];
     59                 ti++;
     60                 tj++;
     61             }
     62             ti = i;
     63             tj = j;
     64             while (ti <= n && tj <= n)
     65             {
     66                 sum[ti][tj] += ss;
     67                 ti++;
     68                 tj++;
     69             }
     70             ti = i;
     71             tj = j;  // 左下
     72             ss = 0;
     73             while (ti <= n && tj >= 1)
     74             {
     75                 ss += board[ti][tj];
     76                 ti++;
     77                 tj--;
     78             }
     79             ti = i;
     80             tj = j;
     81             while (ti <= n && tj >= 1)
     82             {
     83                 sum[ti][tj] += ss;
     84                 ti++;
     85                 tj--;
     86             }
     87         }
     88         // 第 1 列
     89         int j = 1;
     90         for (int i = 2; i <= n; i++)
     91         {
     92             LL ss = 0;
     93             int ti = i;
     94             int tj = j;
     95             while (ti <= n && tj <= n)
     96             {
     97                 ss += board[ti][tj];
     98                 ti++;
     99                 tj++;
    100             }
    101 
    102             ti = i;
    103             tj = j;
    104             while (ti <= n && tj <= n)
    105             {
    106                 sum[ti][tj] += ss;
    107                 ti++;
    108                 tj++;
    109             }
    110         }
    111         j = n;
    112         for (int i = 2; i <= n; i++)
    113         {
    114             LL ss = 0;
    115             int ti = i;
    116             int tj = j;
    117             while (ti <= n && tj >= 1)
    118             {
    119                 ss += board[ti][tj];
    120                 ti++;
    121                 tj--;
    122             }
    123             ti = i;
    124             tj = j;
    125             while (ti <= n && tj >= 1)
    126             {
    127                 sum[ti][tj] += ss;
    128                 ti++;
    129                 tj--;
    130             }
    131         }
    132         int cnt = 0;
    133         for (int i = 1; i <= n; i++)
    134         {
    135             for (int j = 1; j <= n; j++)
    136             {
    137                  num[cnt].x = i;
    138                  num[cnt].y = j;
    139                  num[cnt++].s = sum[i][j] - board[i][j];
    140             }
    141         }
    142         int flag = 0;
    143         LL maxsum;
    144         int x1, y1, x2, y2;
    145         sort(num, num+cnt);
    146         for (int i = cnt-1; i >= 0 && !flag; i--)
    147         {
    148             for (int j = i-1; j >= 0 && !flag; j--)
    149             {
    150                 int t1 = num[i].x + num[i].y;
    151                 int t2 = abs(num[j].x - num[j].y);
    152                 if ((t1 + t2) % 2 == 0)
    153                     continue;
    154                 if (abs(num[i].x-num[j].x) != abs(num[i].y - num[j].y))
    155                 {
    156                     flag = 1;
    157                     x1 = num[i].x, x2 = num[j].x;
    158                     y1 = num[i].y, y2 = num[j].y;
    159                     maxsum = num[i].s + num[j].s;
    160                     break;
    161                 }
    162             }
    163         }
    164         printf("%lld
    ", maxsum);
    165         printf("%d %d %d %d
    ", x1, y1, x2, y2);
    166     }
    167     return 0;
    168 }
    View Code

         

  • 相关阅读:
    异步、作用域、闭包--setTimeout在for循环中的思考
    C++中*和&的定义和使用
    利用border设置transparent绘制图形
    暑假周记四
    暑假周记三
    win10系统下安装Linux虚拟机以及在虚拟机上安装Ubuntu
    暑假周记二
    暑假周记一
    《浪潮之巅》上——阅读笔记06
    《浪潮之巅》上——阅读笔记05
  • 原文地址:https://www.cnblogs.com/windysai/p/3950496.html
Copyright © 2020-2023  润新知