[前缀和][dp] Jzoj P5873 小p的属性
题解
- 把问题转化一下,就是在一个二维的平面上,有些点有权值,你每次都可以向右或者向上走,经过一个点后得到他的权值,并且每走一步都会再次加上他的权值,问你走k步的最大权值是多少
- 我们发现他每次走都会走到某个点上,这样答案才会更优
- 所以我们把所有点的横坐标纵坐标拿出来离散,然后插入点值,这样就可以不用枚举坐标了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 struct edge { int x,y,z; }e[1010]; 6 int n,m,cnt1,cnt2,cnt; 7 long long ans,f[1010][1010],g[1010][1010],l[1010],r[1010]; 8 int find1(int x) 9 { 10 int L=1,R=cnt1; 11 while (L<=R) 12 { 13 int mid=(L+R)>>1; 14 if (l[mid]==x) return mid; 15 if (l[mid]<x) L=mid+1; else R=mid-1; 16 } 17 } 18 int find2(int x) 19 { 20 int L=1,R=cnt2; 21 while (L<=R) 22 { 23 int mid=(L+R)>>1; 24 if (r[mid]==x) return mid; 25 if (r[mid]<x) L=mid+1; else R=mid-1; 26 } 27 } 28 int main() 29 { 30 freopen("growth.in","r",stdin); 31 freopen("growth.out","w",stdout); 32 scanf("%d%d",&n,&m); 33 for (int i=1;i<=n;i++) 34 { 35 int x,y,z; 36 scanf("%d%d%d",&x,&y,&z); 37 if (x+y>m) continue; 38 e[++cnt].x=x,e[cnt].y=y,e[cnt].z=z; 39 l[++cnt1]=x,r[++cnt2]=y; 40 } 41 sort(l+1,l+cnt1+1),sort(r+1,r+cnt2+1); 42 cnt1=unique(l+1,l+cnt1+1)-l-1,cnt2=unique(r+1,r+cnt2+1)-r-1; 43 for (int i=1;i<=cnt;i++) g[find1(e[i].x)][find2(e[i].y)]+=e[i].z; 44 for (int i=1;i<=cnt1;i++) 45 for (int j=1;j<=cnt2;j++) 46 g[i][j]+=g[i-1][j]+g[i][j-1]-g[i-1][j-1]; 47 for (int i=1;i<=cnt1;i++) 48 for (int j=1;j<=cnt2;j++) 49 f[i][j]=g[i][j]+max(f[i-1][j]+(l[i]-l[i-1]-1)*g[i-1][j],f[i][j-1]+(r[j]-r[j-1]-1)*g[i][j-1]); 50 for (int i=1;i<=cnt1;i++) 51 for (int j=1;j<=cnt2;j++) 52 if (l[i]+r[j]<=m) 53 ans=max(ans,f[i][j]+(m-l[i]-r[j])*g[i][j]); 54 printf("%lld",ans); 55 }