CF76F Tourist

调了半天,发现是没开long long

Solution

看这个题的时候,第一想法是按时间排序,然后朴素DP,但这样差不多是 \(O(n^2\cdot v)\) 的。

所以我们需要考虑更优的解法。

不难发现,只有当 \(i,j\) 两点满足 \(|x_i-x_j|\leq |t_i-t_j|\times v\) 时,才可以从一个点到另一个,然后我们尝试去转化这个式子。

\(t_i\leq t_j\) 时,如果 \(x_i\leq x_j\)\(x_j-x_i\leq t_j\times v-t_i\times v\Rightarrow-x_i+t_i\times v\leq -x_j+t_j\times v\)

​ 否则 \(x_i-x_j\leq t_j\times v-t_i\times v\Rightarrow x_i+t_i\times v\leq x_j+t_j\times v\)

\(t_i\geq t_j\) 同理,那么我们设 \(a_i=x_i+t_i\times v,b_i=-x_i+t_i\times v\) ,可以将上面的式子变成 \(a_i\leq a_j,b_i\leq b_j\) ,也就是需要满足这两个条件就可以转移。

然后将 \(a\) 排序,就是LIS问题。

对于第一个问题,只要判断一下 \(a_i,b_i\geq 0\) 就行了。、

时间复杂度: \(O(n\log n)\) ,和普通的LIS问题一样。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long

using namespace std;
const int N=1e5+10;
const ll INF=1e12;
struct node{
    ll a,b;
}mt[N];
ll q[N],x[N],t[N],v;
int n,r,ans1,ans2;

inline bool cmp(node a,node b){
    return a.a==b.a?a.b<b.b:a.a<b.a;
}

int find(int l,int r,ll x){
    int res=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(q[mid]>x) res=mid,r=mid-1;
        else l=mid+1;
    }
    return res;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&x[i],&t[i]);
    scanf("%lld",&v);
    for(int i=1;i<=n;i++){
        mt[i].a=-x[i]+t[i]*v;
        mt[i].b=x[i]+t[i]*v;
    }
    sort(mt+1,mt+1+n,cmp);
    q[0]=-INF,q[++r]=INF;
    for(int i=1;i<=n;i++){
        int pos=find(0,r,mt[i].b);
        if(q[pos]>mt[i].b) q[pos]=mt[i].b;
        if(pos>=r) q[++r]=INF;
    }
    ans2=r-1;
    q[r=1]=INF;
    for(int i=1;i<=n;i++)
        if(mt[i].a>=0&&mt[i].b>=0){
            int pos=find(0,r,mt[i].b);
            if(q[pos]>mt[i].b) q[pos]=mt[i].b;
            if(pos>=r) q[++r]=INF;
        }
    ans1=r-1;
    printf("%d %d\n",ans1,ans2);
    return 0;
}
posted @ 2020-10-14 21:54  jasony_sam  阅读(115)  评论(0编辑  收藏  举报