1 条题解

  • 5
    @ 2023-11-5 20:25:56
    思路 这一道题的数据范围需要最值优化的: $\\$考虑上一题的状态转移方程: $\\ f[i][j]=max(f[j][k]+point[i].s)$ $\\$其中$k<=j<i,x(j)−x(k)≤x(i)−x(j)。$ $\\$通过分离与$k$无关的常量,可以改写为: $\\ f[i][j]=max(f[j][k])+point[i].s$ $\\$其中$k<=j<i,x(j)−x(k)≤x(i)−x(j)$。 $\\$可以定义$val$为满足这个范围中的$f[j][k]$的最大值。 $\\$但是我们会发现如果我们固定$i$,增加$j$取值时,由于第一个条件$k<=j<i$.$k$的取值范围会增加,但是因为第二个条件$x(j)−x(k)≤x(i)−x(j)$,$k$的取值范围反而会减少。 $\\$但是如果我们固定$j$,增加$i$取值时,$k$的取值范围会一直增加,因为有上界$j$。所以我们可以更改循环顺序,外层循环$j$,中层循环$i$,然后使用$while$循环,添加$i$增加时新符合要求的$k$,最后用$val$维护$f[i][j]$ $\\$这种做法虽然还是3层循环,但是无论是当外层循环变量$j$固定时,最内层的$k$只会最多从$j-1$遍历到$1$。真实的时间复杂度只有$O(n^2)$
    代码
    
    #include <bits/stdc++.h>
    using namespace std;
    const int N=2005;
    int n,f[N][N],ans;
    struct Point{
    	int x,s;
    } point[N];
    bool cmp(Point a,Point b)
    {
    	return a.x<b.x;
    }
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++) 
    		cin>>point[i].x>>point[i].s;
    	sort(point+1,point+1+n,cmp);
    	for(int j=1;j<=n;j++)
    	{
    		f[j][j]=point[j].s;
    		int val=f[j][j]; 
    		int k=j;
    		for(int i=j+1;i<=n;i++)
    		{
    			while(((point[i].x-point[j].x)>=(point[j].x-point[k].x))&&k>0)
    			{
    				val=max(val,f[j][k]);
    				k--;
    			}
    			f[i][j]=val+point[i].s;
    			ans=max(ans,f[i][j]);
    		}
    	}
    	for(int j=n;j>=1;j--)
    	{
    		int val=f[j][j];
    		int k=j;
    		for(int i=j-1;i>=1;i--)
    		{
    			while(((point[j].x-point[i].x)>=(point[k].x-point[j].x))&&k<=n)
    			{
    				val=max(val,f[j][k]);
    				k++;
    			}
    			f[i][j]=val+point[i].s;
    			ans=max(ans,f[i][j]);
    		}
    	}
    	cout<<ans;
    }
    
    
    • 1

    信息

    ID
    553
    时间
    1000ms
    内存
    256MiB
    难度
    1
    标签
    (无)
    递交数
    144
    已通过
    101
    上传者