这次应该叫高二上几调?
作者:互联网
B. biology
错误思路:按a的值分个层,直接把每层的最大值的点编号放到队列里,后来忽然发现每个a最小一层的点都有可能当一次起点,它的位置决定了后面的点的位置,不能单独考虑起点b值的大小,于是就让每一个最小的a当一次起点循环一遍。我已经做好了它超时的心理准备,但是有WA的点就不太理解。。。如果有读者能指出错因我会很感谢的。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 4e6 + 3; const int N = 1e7 + 2; const ll INF = 1e17; int n, m, q[maxn], l=1, r, num, pos, hv[maxn], cnt; ll ans; struct node { int x, y, a, b; bool operator < (const node &T) { return a < T.a; } }p[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); m = read(); //printf("n=%d m=%d\n", n, m); for(int i=1; i<=n; i++) { for(int j=1; j<=m ;j++) { p[++num].a = read(); //printf("p[%d].a = %d\n", num, p[num].a); p[num].x = i; p[num].y = j; } } num = 0; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { p[++num].b = read(); } } sort(p+1, p+1+num); //printf("%d", p[1].a); for(int i=1; i<=num; i++) { if(p[i].a) { pos = i; break; } } q[++r] = pos; hv[++cnt] = pos; for(int i=pos+1; i<=num; i++) { //printf("p[%d].a = %d\n", i, p[i].a); //printf("cmp : %d %d\n", p[i].a, p[q[1]].a); if(p[i].a == p[q[1]].a) { hv[++cnt] = i; pos = i; } else break; } //printf("cnt=%d\n", cnt); for(int k=1; k<=cnt; k++) { ll sum = 0; l = 1, r = 0; q[++r] = hv[k]; for(int i=pos+1; i<=num; i++) { if(p[i].a > p[q[r]].a) q[++r] = i; else if(p[i].a == p[q[r]].a) { if(r == 1) { continue; } else if((ll)p[i].b+abs(p[i].x-p[q[r-1]].x)+abs(p[i].y-p[q[r-1]].y) > (ll)p[q[r]].b+abs(p[q[r]].x-p[q[r-1]].x)+abs(p[q[r]].y-p[q[r-1]].y)) { q[r] = i; } } } sum += p[q[1]].b; for(int i=2; i<=r; i++) { sum += (ll)p[q[i]].b+abs(p[q[i]].x-p[q[i-1]].x)+abs(p[q[i]].y-p[q[i-1]].y); } //printf("sum=%lld\n", sum); ans = max(ans, sum); } /*for(int i=pos+1; i<=num; i++) { if(p[i].a > p[q[r]].a) q[++r] = i; else if(p[i].a == p[q[r]].a) { if(r == 1) { if(p[i].b > p[q[r]].b) q[r] = i; } else if((ll)p[i].b+abs(p[i].x-p[q[r-1]].x)+abs(p[i].y-p[q[r-1]].y) > (ll)p[q[r]].b+abs(p[q[r]].x-p[q[r-1]].x)+abs(p[q[r]].y-p[q[r-1]].y)) { q[r] = i; } } }*/ /*ans += p[q[1]].b; for(int i=2; i<=r; i++) { ans += (ll)p[q[i]].b+abs(p[q[i]].x-p[q[i-1]].x)+abs(p[q[i]].y-p[q[i-1]].y); }*/ printf("%lld", ans); return 0; }只有30分
然后就是题解了:
第一步还是分层,但这个分层是放到数组里,而不是在脑海中。预处理的标准是每一个层号都能找到这一层的数值,而每一层的数值也能对应回层的编号。
dp[i][j] 表示当前路径的结尾在(i, j)位置的最大吸引度之和。 f[i][j] = max{f[i'][j'] + b[i'][j'] + ∣i − i ∣ + ∣j − j ∣, a[i][j] = a[i'][j'] + x, x>=1} 。
把绝对值拆开:f[i][j]可能为f[i'][j']+b[i'][j']-i'-j'+i+j或f[i'][j']+b[i'][j']+i'+j'-i-j或f[i'][j']-i'+j'+i-j或f[i'][j']+i'-j'+i+j。所以坐标转换,把(i+j, i-j)放进a[i][j]属于的分层,再用四个变量维护一下i'和j'的四种对应情况随递推的变化,递推时对应决定了当前的i和j应该加还是应该减。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e3 + 2; const int N = 4e6 + 3; const ll INF = 1e17; int a[maxn][maxn], b[maxn][maxn], n, m; int rec[N], pos[N], cnt; ll dp[maxn][maxn], ans, maxx[5]; bool vis[N]; vector<pair<int, int> > v[N]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); m = read(); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { a[i][j] = read(); if(!a[i][j]) continue; if(!vis[a[i][j]]) rec[++cnt] = a[i][j]; vis[a[i][j]] = 1; } } sort(rec+1, rec+1+cnt); for(int i=1; i<=cnt; i++) pos[rec[i]] = i; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { b[i][j] = read(); } } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(!a[i][j]) continue; v[pos[a[i][j]]].push_back(make_pair(i+j, i-j)); } } for(int i=0; i<(int)v[1].size(); i++) { ll p = v[1][i].first, q = v[1][i].second; ll valb = b[(p+q)>>1][(p-q)>>1];//用原坐标的b值 maxx[1] = max(maxx[1], valb-p); maxx[2] = max(maxx[2], valb+p); maxx[3] = max(maxx[3], valb-q); maxx[4] = max(maxx[4], valb+q); } for(int i=2; i<=cnt; i++) { for(int j=0; j<(int)v[i].size(); j++) { ll p = v[i][j].first, q = v[i][j].second; ll valb = b[(p+q)>>1][(p-q)>>1]; //b'-i'-j'+b+i+j //b'+i'+j'+b-i-j //b'-i'+j'+b+i-j //b'+i'-j'+b-i+j dp[(p+q)>>1][(p-q)>>1] = max(max(maxx[1]+valb+((p+q)>>1)+((p-q)>>1), maxx[2]+valb-((p+q)>>1)-((p-q)>>1)), max(maxx[3]+valb+((p+q)>>1)-((p-q)>>1), maxx[4]+valb-((p+q)>>1)+((p-q)>>1))); } for(int j=0; j<(int)v[i].size(); j++) { ll p = v[i][j].first, q = v[i][j].second; ll valdp = dp[(p+q)>>1][(p-q)>>1]; maxx[1] = max(maxx[1], valdp-p);//b-i-j maxx[2] = max(maxx[2], valdp+p); maxx[3] = max(maxx[3], valdp-q); maxx[4] = max(maxx[4], valdp+q); } } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { ans = max(ans, dp[i][j]); } } printf("%lld\n", ans); return 0; }感谢WR大佬
标签:几调,maxx,ch,高二上,这次,max,ll,int,maxn 来源: https://www.cnblogs.com/Catherine2006/p/16479034.html