题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3962
这个玩意,貌似可以暴力?
预处理出斜着的线上的点有多少,这样在暴力转移的时候,可以做到O(1)
然后就是写代码的事情了,然而写了两个小时了,没写出来QAQ
弃疗………..
—– 2016.9.6 更新 —–
耐着性子码完了代码
为什么觉得线段求交点常数大?
为什么要作死直接分类讨论 (╯‵□′)╯︵┻━┻
#include<bits/stdc++.h> #define LL long long #define abs(x) ((x)>0?(x):-(x)) using namespace std; const int N = 1000+9; int n,m,q,sz,head[N],vout,X,Y; int mat[N][N],f[2][N][N]; inline int read(){ char c=getchar(); int ret=0,f=1; while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); return ret*f; } inline void prework(){ for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) f[0][i][j] = f[0][i-1][j-1] + mat[i][j]; for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) f[1][i][j] = f[1][i+1][j-1] + mat[i][j]; } inline int pro(int x1, int y1, int x2, int y2, int t) { int ret = 0; if (!t) { x2--; y2--; if (x1 < 1 || y1 < 1) ret += 0; else if (x1 <= n && y1 <= m) ret += f[t][x1][y1]; else if (x1 > n) ret += (y1-(x1-n)<=m && y1-(x1-n)>=1)? f[t][n][y1-(x1-n)]: 0; else ret += (1<=x1-(y1-m) && x1-(y1-m)<=n)? f[t][x1-(y1-m)][m]: 0; if (x2 < 1 || y2 < 1) ret -= 0; else if (x2 <= n && y2 <= m) ret -= f[t][x2][y2]; else if (x2 > n) ret -= (y2-(x2-n)<=m && y2-(x2-n)>=1)? f[t][n][y2-(x2-n)]: 0; else ret -= (1<=x2-(y2-m) && x2-(y2-m)<=n)? f[t][m][2-(y2-m)]: 0; } else { x2++; y2--; if (x1 > n || y1 < 1) ret += 0; else if (x1 >= 1 && y1 <= m) ret += f[t][x1][y1]; else if (x1 < 1) ret += (y1-(1-x1)>=1 && y1-(1-x1)<=m)? f[t][1][y1-(1-x1)]: 0; else ret += (x1+(y1-m)>=1 && x1+(y1-m)<=n)? f[t][x1 + (y1 - m)][m]: 0; if (x2 > n || y2 < 1) ret -= 0; else if (x2 >= 1 && y2 <= m) ret -= f[t][x2][y2]; else if (x2 < 1) ret -= (y2-(1-x2)>=1 && y2-(1-x2)<=m)? f[t][1][y2 -(1-x2)]: 0; else ret -= (1<=x2+(y2-m) && x2+(y2-m)<=n)? f[t][x2+(y2-m)][m]: 0; } return ret; } inline void solve(int lim){ vout = 0; X = 1; Y = 1; for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) if (i + j > lim + 2) break; else vout += mat[i][j]; head[1] = vout; int tmp = vout; for (int j=1;j<=m;j++) { for (int i=1;i<n;i++) { tmp += pro(i+lim+1,j,i+1,j-lim,0); // ¨J tmp -= pro(i,j+lim,i-lim,j,0); // ¨L tmp += pro(i+1,j+lim,i+lim+1,j,1); // ¨K tmp -= pro(i-lim,j,i,j-lim,1); // ¨I if (i + lim + 1 <= n) tmp -= mat[i+lim+1][j]; if (i - lim >= 1) tmp += mat[i-lim][j]; if (tmp > vout) vout = tmp, X = i+1, Y = j; } if (j < m) { tmp = head[j]; tmp += pro(1,j+lim+1,1+lim,j+1,1);//¨K tmp += pro(1,j+lim+1,1-lim,j+1,0);//¨L tmp -= pro(1+lim,j,1,j-lim,0);//¨J tmp -= pro(1-lim,j,1,j-lim,1);//¨I if (j + lim + 1 <= m) tmp -= mat[1][j+lim+1]; if (j - lim >= 1) tmp += mat[1][j-lim]; if (tmp > vout) vout = tmp, X = 1, Y = j+1; head[j+1] = tmp; } } } inline void init(int w){ memset(f,0,sizeof(f)); memset(mat,0,sizeof(mat)); printf("Case %d:\n",w); } int main(){ for (int T=1;scanf("%d%d",&n,&m) && n && m;T++) { init(T); sz = read(); q = read(); for (int i=1,x,y;i<=sz;i++) x = read(), y = read(), mat[x][y]++; prework(); for (int k=1;k<=q;k++) { solve(min(m+n,read())); printf("%d (%d,%d)\n",vout,X,Y); } } return 0; }
然而DZY告诉我们,这货可以变成正方形?
参见:http://dzy493941464.is-programmer.com/posts/86498.html
仔细想了一想:我们可以通过将整个图旋转45°,然后重新编号,然后就变成了正方形?
然后就是很常规的滑动窗口了?
—– UPD 2016.6.9 —–
坐标旋转的代码
#include<bits/stdc++.h> using namespace std; const int N = 2000+9; int n,k,q,mat[N][N],sta[N],sum[N][N],MX; inline int read(){ char c=getchar(); int ret=0,f=1; while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} return ret*f; } #define SUM(x,y) sum[max(0,min(x,MX))][max(0,min(y,MX))] inline void solve(int lim) { int vout = 0; for (int j=1;j<=n;j++) for (int i=1,x,y;i<=n;i++) x = sta[i]-j+1, y = i+j-1, vout = max(vout, SUM(x+lim,y+lim) + SUM(x-lim-1,y-lim-1) - SUM(x+lim,y-lim-1) - SUM(x-lim-1,y+lim)); printf("%d\n",vout); } int main(){ n = read(); k = read(); q = read(); MX = n * 2 - 1; sta[1] = n; for (int i=2;i<=n;i++) sta[i] = sta[i-1] + 1; for (int i=n+1;i<=n*2-1;i++) sta[i] = sta[i-1] - 1; for (int i=k,x,y;i;--i) x = read(), y = read(), mat[sta[x]-y+1][x+y-1] = 1; for (int j=1;j<=MX;j++) for (int i=1;i<=MX;i++) sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + mat[i][j]; for (int i=1;i<=q;i++) solve(read()); return 0; }