土地購買

wlesq發表於2024-06-10

image
首先我們可以打一個暴力,複雜度為\(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;
}

相關文章