• P5468 [NOI2019]回家路线 斜率优化 dp


    LINK:回家路线

    (文化课 oi 双爆炸 对 没学上的就是我。(我错了不该这么丧的.

    不过还能苟住一段时间。当然是去打NOI了

    这道题去年同步赛的时候做过。不过这里再次提醒自己要认真仔细的看题目 不要理解错题目的意思 导致测大样例的时候才发现自己的漏洞。导致时间上的浪费。

    题目的本身还是极好的 容易得到一个(m^2)的dp做法. 进一步的可以得到一个(mq)的做法。由于数据过水 所以这样做就能过了。

    (当然不会告诉你去年我写了一个nqlog的做法水过去了

    考虑优化 还是对m这个东西进行dp 对序列dp很难受 状态数量至少是nq的。

    观察贡献的式子 容易发现是斜率优化的标准式子 考虑对于端点y那些决策进行斜率优化。

    需要考虑清楚几个问题:对于横坐标要从小到大加。所以需要排序 考虑对于贡献 排序后斜率和对于贡献的i都是递增的 这就可以很方便的使用单调队列维护了。

    斜率优化要处理的最重要的一个细节是斜率不存在问题 特判或者强行删点 我使用的是后者。

    时间复杂度为mlogm 瓶颈在于排序。

    可以利用桶排序优化到线性 不过这样常数也很大没什么必要...

    也可用通过luogu的加强版。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<ctime>
    #include<cstdlib>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<utility>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #include<deque>
    #include<stack>
    #include<list>
    #include<bitset>
    #include<set>
    #include<map>
    #define INF 1000000000000000000ll
    #define rep(p,n,i) for(int i=p;i<=n;++i)
    #define fep(n,p,i) for(int i=n;i>=p;--i)
    #define vep(p,n,i) for(int i=p;i<n;++i)
    #define db double
    #define get(x) x=read()
    #define put(x) printf("%d
    ",x)
    #define pb push_back
    #define ll long long
    #define db double
    #define putl(x) printf("%lld
    ",x)
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char getc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	int x=0,f=1;char ch=getc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    	return x*f;
    }
    const int MAXN=1000010,maxn=100010;
    int n,m;ll A,B,C,D;
    int a[MAXN],L[maxn],R[maxn];
    ll f[MAXN],v[MAXN];
    struct wy{int x,y,p,q;}t[MAXN];
    inline int cmp(wy a,wy b){return a.p<b.p;}
    inline int cmp1(int a,int b){return t[a].q<t[b].q;}
    vector<int>g[maxn];
    inline db slope(int a,int b)
    {
    	return (db)(v[a]-v[b])/(db)(t[a].q-t[b].q);
    }
    inline void insert(int x)
    {
    	int p=t[x].y;v[x]=f[x]-B*t[x].q+A*t[x].q*t[x].q;
    	//加入g[p].
    	if(L[p]<=R[p])
    	{
    		if(t[g[p][R[p]]].q==t[x].q)
    		{
    			if(v[g[p][R[p]]]<v[x])return;
    			g[p].pop_back();--R[p];
    		}
    	}
    	while(L[p]<R[p]&&slope(g[p][R[p]],g[p][R[p]-1])>=slope(x,g[p][R[p]]))--R[p],g[p].pop_back();
    	g[p].pb(x);++R[p];
    }
    inline ll calc(int x){return x*A*x+B*x+C;}
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(n);get(m);get(A);get(B);get(C);
    	rep(1,m,i)
    	{
    		int get(x),get(y);
    		int get(p),get(q);
    		t[i]=(wy){x,y,p,q};a[i]=i;
    	}
    	rep(1,n,i)L[i]=0,R[i]=-1;
    	sort(t+1,t+1+m,cmp);
    	sort(a+1,a+1+m,cmp1);
    	int flag=1;ll ans=INF;
    	rep(1,m,i)
    	{
    		while(flag<=m&&t[a[flag]].q<=t[i].p)
    		{
    			if(f[a[flag]]!=-1)insert(a[flag]);
    			++flag;
    		}
    		int p=t[i].x;f[i]=-1;
    		if(t[i].x==1)f[i]=calc(t[i].p);
    		while(L[p]<R[p]&&slope(g[p][L[p]+1],g[p][L[p]])<=2*A*t[i].p)++L[p];
    		if(L[p]<=R[p])f[i]=calc(t[i].p-t[g[p][L[p]]].q)+f[g[p][L[p]]];
    		if(f[i]!=-1&&t[i].y==n)ans=min(ans,f[i]+t[i].q);
    	}
    	putl(ans);
    	return 0;
    }
    
  • 相关阅读:
    图像的剪切
    DOS指令大全(二)
    扫描进程
    数据库名、数据库实例、全局数据库名、服务名、SID等的区别
    ORA29807: specified operator does not exist
    TCP/IP网络编程的几个网站
    漂在等待离职的日子(三)
    入职第一天
    入职一周
    漂在等待离职的日子(八)
  • 原文地址:https://www.cnblogs.com/chdy/p/13199690.html
Copyright © 2020-2023  润新知