首先我們可以打一個暴力,複雜度為\(O(n^3)\)
\(f[i]=min(f[i],f[j]+len_{max} \times wid_{max})\)
點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pb push_back
#define pf push_front
#define lid (rt<<1)
#define rid (rt<<1|1)
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 5e4+5;
ll n,f[N];
inline ll read()
{
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
struct ac
{
ll len,wid;
}a[N];
bool cmp(ac a,ac b)
{
return a.len<b.len;
}
int main()
{
// speed();
n=read();
for(int i=1;i<=n;i++)
{
a[i].len=read();a[i].wid=read();
// cin>>a[i].len>>a[i].wid;
}
sort(a+1,a+1+n,cmp);
memset(f,0x3f,sizeof f);
f[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
ll le=0,w=0;
for(int k=j+1;k<=i;k++)
{
le=max(a[k].len,le);
w=max(a[k].wid,w);
}
// cout<<le<<" "<<w<<endl;
f[i]=min(f[i],f[j]+le*w);
}
}
cout<<f[n];
return 0;
}
首先,len單調遞增排過序了
如何最佳化呢,我們可以除去一些無用的土地,即\(i>j且len_i>len_j且 wid_i>wid_j\)則\(j\)是無用的
這樣我們篩選完以後,就無需找最大值最小值
\(F[i]=min(f[j]+acc[j+1].wid*acc[i].len)\)
但這樣仍然過不了
點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pb push_back
#define pf push_front
#define lid (rt<<1)
#define rid (rt<<1|1)
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 5e4+5;
ll n,f[N],q[N],cnt;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
struct ac
{
ll len,wid;
}a[N],acc[N];
bool cmp(ac a,ac b)
{
if(a.len==b.len)return a.wid<b.wid;
return a.len<b.len;
}
int main()
{
// speed();
n=read();
for(int i=1;i<=n;i++)
{
a[i].len=read();a[i].wid=read();
// cin>>a[i].len>>a[i].wid;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
while(cnt&&acc[cnt].wid<=a[i].wid)cnt--;
++cnt;
acc[cnt].len=a[i].len;
acc[cnt].wid=a[i].wid;
}
memset(f,0x3f,sizeof f);
f[0]=0;
for(int i=1;i<=cnt;i++)
{
// int l=1,r=1;
for(int j=0;j<i;j++)
{
//// cout<<le<<" "<<w<<endl;
f[i]=min(f[i],f[j]+acc[i].len*acc[j+1].wid);
}
// while(l<r&&)
}
// for(int i=1;i<=cnt;i++)ans=min(ans,f[i]);
cout<<f[cnt];
return 0;
}
我們可以再加上斜率最佳化
斜率為\(-acc[i].len\)
自變數\(acc[j+1].wid\)
因變數\(F[i]\)
點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pb push_back
#define pf push_front
#define lid (rt<<1)
#define rid (rt<<1|1)
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 5e4+5;
ll n,f[N],q[N],cnt;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
struct ac
{
ll len,wid;
}a[N],acc[N];
bool cmp(ac a,ac b)
{
if(a.len==b.len)return a.wid<b.wid;
return a.len<b.len;
}
double X(int i)
{
return acc[i+1].wid*1.0;
}
double Y(int i)
{
return f[i]*1.0;
}
int main()
{
// speed();
n=read();
for(int i=1;i<=n;i++)
{
a[i].len=read();a[i].wid=read();
// cin>>a[i].len>>a[i].wid;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
while(cnt&&acc[cnt].wid<=a[i].wid)cnt--;
++cnt;
acc[cnt].len=a[i].len;
acc[cnt].wid=a[i].wid;
}
memset(f,0x3f,sizeof f);
f[0]=0;int l=1,r=1;
for(int i=1;i<=cnt;i++)
{
// for(int j=0;j<i;j++)
// {
// f[i]=min(f[i],f[j]+acc[i].len*acc[j+1].wid);
// }
while(l<r&&(Y(q[l+1])-Y(q[l]))<=-acc[i].len*(X(q[l+1])-X(q[l])))l++;
f[i]=f[q[l]]+acc[i].len*acc[q[l]+1].wid;
while(l<r&&(Y(q[r])-Y(q[r-1]))*(X(i)-X(q[r]))<=(Y(i)-Y(q[r]))*(X(q[r])-X(q[r-1])))r--;
q[++r]=i;
}
// for(int i=1;i<=cnt;i++)ans=min(ans,f[i]);
cout<<f[cnt];
return 0;
}