看这道题的时候,感觉很难,因为数据范围比较大,很难dp;
后来想到了【书柜的尺寸】这道题,也是一道dp,曾经看了那道题的题解而深有启发;
这道题每组的付费只与这一组长宽的最大值有关,也就是说要分组,一定从按长或宽的从大到小(从小到大也可以)排序,这样剔除无用的数据后,就只剩下一串数据,长从大到小,宽从小到大;
然后我们要在这里面分组,可以轻易发现,一个组的成员一定是连续的,原因与单调性有关;
这样就成了经典的dp,加上一个斜率优化即可轻松水过;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<algorithm> 7 using namespace std; 8 const int maxn=50500; 9 #define LL long long 10 int n,q[maxn]; 11 struct node{ 12 int x,y; 13 bool operator<(const node& c)const{return (x>c.x)||(x==c.x&&y>c.y);} 14 }a[maxn],b[maxn]; 15 LL f[maxn]; 16 double col(int j,int k){return double(f[k]-f[j])/double(b[j+1].x-b[k+1].x);} 17 void init(){ 18 scanf("%d",&n); 19 for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y); 20 sort(a+1,a+n+1);int head=1,tail=0; 21 b[++tail]=a[1]; 22 for(int i=2;i<=n;i++)if(a[i].y>b[tail].y)b[++tail]=a[i]; 23 n=tail; 24 head=1,tail=0;q[++tail]=0; 25 for(int i=1;i<=n;i++){ 26 while(head<tail&&col(q[head],q[head+1])<=b[i].y)head++; 27 f[i]=f[q[head]]+(LL)b[q[head]+1].x*b[i].y; 28 while(head<tail&&col(q[tail],i)<=col(q[tail],q[tail-1]))tail--; 29 q[++tail]=i; 30 } 31 cout<<f[n]<<endl; 32 } 33 int main(){ 34 init(); 35 }