Codeforces 463C Gargari and Bishops 贪心+规律

来源:互联网 发布:mac 复制照片到u盘 编辑:程序博客网 时间:2024/06/06 03:11

点击打开链接

题意:n*n格子 n<=2e3,每个格子有价值a[i][j] 放两个的Bishop,使得任意一个cell都不会同时被两个bishop攻击,Bishop会攻击对角线上的元素并得到价值a[i][j],求能得到的最大价值  

同一条主对角线i-j+n相同,同一条副对角线i+j相同,先根据每个点处理出这个点被选为bishop时所能得到的值



xjb贪心:先选中最大价值的f+g,由于第二个bishop的攻击范围不能与第一个bishop有重叠,把第一个bishop所攻击的坐标设为-inf,在选出次大即可 

标准贪心:由于任意一个cell都不会同时被两个bishop攻击,把board想象成间隔相邻的黑白棋盘,则所选的两个bishop位置颜色必须不同 即i+j的奇偶性必须不同,在odd和even各选一个最大即可.

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=2e3+20;const ll inf=-1e12;ll n,a[N][N];int main(){while(cin>>n){ll f[3*N],g[3*N];//f[i],主对角线x-y+n==i上的总得分 for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){scanf("%I64d",&a[i][j]);f[i-j+n]+=a[i][j];g[i+j]+=a[i][j];}}int x1=1,y1=1,x2=1,y2=2;ll best=0,better=0;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){ll s=f[i-j+n]+g[i+j]-a[i][j];if(s>best){best=s;x1=i;y1=j;}}}memset(f,0,sizeof(f));memset(g,0,sizeof(g));for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i+j==x1+y1||i-j+n==x1-y1+n){a[i][j]=inf;}f[i-j+n]+=a[i][j];g[i+j]+=a[i][j];}}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){ll s=f[i-j+n]+g[i+j]-a[i][j];if(better<s){better=s;x2=i;y2=j;}}}ll ans=best+better;cout<<ans<<endl;cout<<x1<<' '<<y1<<' '<<x2<<' '<<y2<<endl;}return 0;} 

标准做法(转)

#include <stdio.h>  #include <vector>  #include <string.h>  #include <algorithm>  #include <iostream>  #include <string>  #include <limits.h>  #include <stack>  #include <queue>  #include <set>  #include <map>  using namespace std;    long long d1[4100], d2[4100];  long long arr[2100][2100];  int N;    int main()  {      scanf("%d", &N);      for (int i = 1; i <= N; i++)      {          for (int j = 1; j <= N; j++)          {              scanf("%I64d", &arr[i][j]);              d1[i+j] += arr[i][j];//注意记熟斜对角线的计算表示方法              d2[i-j+N] += arr[i][j];          }      }      for (int i = 1; i <= N; i++)      {          for (int j = 1; j <= N; j++)          {              arr[i][j] = d1[i+j] + d2[i-j+N] - arr[i][j];//巧妙地求本格的交叉          }      }      int c[4] = {1, 1, 1, 2};      for (int i = 1; i <= N; i++)      {//一个间隔有条件组合抽象思维          for (int j = 1; j <= N; j++)          {              if ((i+j) & 1)//巧用奇偶排除相互attack的条件              {                  if (arr[i][j] > arr[c[2]][c[3]]) c[2] = i, c[3] = j;              }              else if (arr[i][j] > arr[c[0]][c[1]]) c[0] = i, c[1] = j;          }//选择符合条件的两个最大值组合起来      }      long long res = arr[c[0]][c[1]] + arr[c[2]][c[3]];      printf("%I64d\n%d %d %d %d\n", res, c[0], c[1], c[2], c[3]) ;      return 0;  }  



0 0
原创粉丝点击