f[i][s]代表前i个人已经分了s组
按w从大到小排序,h从小到大,并且筛掉w、h都小的
也就是说w不递增,h递增。
f[i][s]=f[j][s-1]+a[j+1].w*a[i].h;
按w从大到小排序,h从小到大,并且筛掉w、h都小的
也就是说w不递增,h递增。
f[i][s]=f[j][s-1]+a[j+1].w*a[i].h;
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50005
using namespace std;
typedef long long LL;
const LL inf=1ll<<60;
int b[N];
LL f[N],f0[N];
int n,o,p,m;
bool v[N];
struct node{
int w,h;
}a[N];
bool cmp(node a,node b)
{
if (a.w>b.w) return 1;
if (a.w<b.w) return 0;
if (a.h<b.h) return 1;
if (a.h>=b.h) return 0;
}
inline LL g(int j,int k) //j>k
{ return f0[j]-f0[k];
}
inline LL s(int j,int k) //j>k&& RE>0
{ return a[k+1].w-a[j+1].w;
}
inline bool ok(int j,int k,LL t) //j>k
{
if (g(j,k)<=s(j,k)*t) return 1;
return 0;
}
void insert(int x,LL t)
{ bool flag;
o++;b[o]=x;
if (o-p>=2) flag=g(b[o-2],b[o-1])*s(b[o-1],b[o])>=g(b[o-1],b[o])*s(b[o-2],b[o-1]); else flag=0;
while (flag)
{
b[o-1]=b[o]; o--;
if (o-p>=2) flag=g(b[o-2],b[o-1])*s(b[o-1],b[o])>=g(b[o-1],b[o])*s(b[o-2],b[o-1]); else flag=0;
}
if (o-p>=1) flag=ok(b[p+1],b[p],t);else flag=0;
while (flag)
{
p++;
if (o-p>=1) flag=ok(b[p+1],b[p],t);else flag=0;
}
}
void doit()
{
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i].w,&a[i].h);
sort(a+1,a+n+1,cmp);
int j=1;
for(int i=2; i <= n; i++)
{
if(a[i].h<=a[j].h) continue;
++j;
a[j] = a[i];
}
n=j;
if(m>n) m=n;
for (int i=1;i<=n;i++)
f0[i]=LL(a[1].w)*a[i].h;
f0[0]=0;
for (int ii=2;ii<=m;ii++)
{ b[1]=0; o=1; p=1;
for (int i=1;i<=n;i++)
{ int j=b[p];
f[i]=f0[j]+LL(a[j+1].w)*a[i].h;
insert(i,a[i+1].h);
}
for (int i=1;i<=n;i++)
f0[i]=f[i];
}
printf("%I64d\n",f0[n]);
}
int main()
{ while (scanf("%d%d",&n,&m)!=EOF)doit();
return 0;
}