problem:
给一个n*m的矩阵,每个cell有个值。定义一种cricle,半径为r(这个我就不解释了。。)。选两个没有公共cell的circle使其和最大,并输出有多少中选择。
think
1.预处理每个circle的值。n^3. 这个先存一下每一列sum(a(i,1) + a(i,2) + …… + a(i,j))。然后找到圆心为(i,j)这个circle的第ii行时,可以O(1)得到他的横向长度。
2.预处理每行的左端最大circle值和右端最大circle值。n^2. max(val(i,1), val(i,2), ……, val(i,j)) 和 the quatity of (val[i][jj] == L[i][j])
3.预处理nn[i] = j. n^2. 表示i*i+j*j<=r*r.用于预处理下面的diff数组。方法暴力搞就行。
4.预处理diff[i] = j. n^3. 表示当圆心列数与某circle相差i时,行数最少相差j。方法暴力搞就行。
default:
1.如果不予处理diff数组,而用sqrt(2*r*2*r - (i-ii)*(i-ii)) 这样,会一直 WA 在 test20.
2.num会爆int
code
const int N = 505;
int n, m, r;
int a[N][N];//the input
int val[N][N];//every circle value of i,j
int lft[N][N];//sum(a(i,1) + a(i,2) + …… + a(i,j)) for the array of "val"
int L[N][N];//max(val(i,1), val(i,2), ……, val(i,j))
LL numL[N][N];//the quatity of (val[i][jj] == L[i][j])
int R[N][N];//max(val(i,n), val(i,n-1), ……, val(i,j))
LL numR[N][N];//the quatity of (val[i][jj] == R[i][j])
int nn[N];//nn[i] = j; //i*i + j*j <= r
int diff[N];//
int main(){
memset(lft, 0, sizeof(lft));
memset(val, 0, sizeof(val));
memset(L, 0, sizeof(L));
memset(R, 0, sizeof(R));
memset(numL, 0, sizeof(numL));
memset(numR, 0, sizeof(numR));
scanf("%d%d%d", &n, &m, &r);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
scanf("%d", &a[i][j]);
lft[i][j] = lft[i][j-1] + a[i][j];
}
}
memset(val, 0, sizeof(val));
for(int i = r+1; i <= n-r; ++i){
for(int j = r+1; j <= m-r; ++j){
for(int ii = - r; ii <= r; ++ii){
int jj = sqrt(r*r - ii*ii);
val[i][j] += lft[i+ii][j+jj] - lft[i+ii][j-jj-1];
}
if(val[i][j] == L[i][j-1]) {
L[i][j] = L[i][j-1];
numL[i][j] = numL[i][j-1] + 1LL;
}
else if(val[i][j] < L[i][j-1]){
L[i][j] = L[i][j-1];
numL[i][j] = numL[i][j-1];
}
else {
L[i][j] = val[i][j];
numL[i][j] = 1LL;
}
}
}
for(int i = r+1; i <= n-r; ++i){
for(int j = m-r; j >= r+1; --j){
if(val[i][j] == R[i][j+1]) {
R[i][j] = R[i][j+1];
numR[i][j] = numR[i][j+1] + 1LL;
}
else if(val[i][j] < R[i][j+1]){
R[i][j] = R[i][j+1];
numR[i][j] = numR[i][j+1];
}
else {
R[i][j] = val[i][j];
numR[i][j] = 1LL;
}
}
}
memset(nn, 0, sizeof(nn));
for(int i = 0; i <= r; ++i){
int j = 0;
while(j*j + i*i <= r*r) ++j;
nn[i] = j-1;
}
for(int i = 0; i <= r*2; ++i){
int tmp = 0;
for(int j = 0; j <= r; ++j){
if(j > r || j < i - r) continue;
tmp = max(tmp, nn[j] + 1 + nn[abs(i-j)]);
}
diff[i] = tmp;
}
int ans = 0;
LL num = 0LL;
for(int i = r+1; i <= n-r; ++i){
for(int j = r+1; j <= m-r; ++j){
for(int ii = r+1; ii <= n-r; ++ii){
int tmp;
if(ii-i-1 >= 2*r || i - ii-1 >= 2*r){
tmp = val[i][j] + L[ii][m-r];
if(tmp==ans){
num += numL[ii][m-r];
}
else if(tmp > ans){
ans = tmp;
num = numL[ii][m-r];
}
continue;
}
int tmpii = abs(i - ii);
int tmpjj = diff[tmpii];
int jj = j - tmpjj;
if(jj >= r+1) {
tmp = val[i][j] + L[ii][jj];
if(tmp==ans){
num += numL[ii][jj];
}
else if(tmp > ans){
ans = tmp;
num = numL[ii][jj];
}
}
jj = j + tmpjj;
if(jj <= m-r){
tmp = val[i][j] + R[ii][jj];
if(tmp==ans){
num += numR[ii][jj];
}
else if(tmp > ans){
ans = tmp;
num = numR[ii][jj];
}
}
}
}
}
if(num==0) puts("0 0");
else printf("%d %I64d\n", ans, num/2LL);
return 0;
}