zoukankan      html  css  js  c++  java
  • 【杭电多校round3】G Interstellar Travel

    题意

    给定二维平面上的n个点,保证只有一个点(P_1)横坐标最小,一个点横坐标最大(P_n),在坐标轴上其余点无序且可能重合
    即 y_1=y_n=0, 0=x_1<x_2,x_3,...,x_n−1<x_n
    要沿着x严格递增的方式选择一些降落点,从P_1走到P_n
    从i点起飞到j点降落,花费的代价是x_i×y_j−x_j×y_i ,
    求花费代价最小的方案,输出字典序最小的答案

    分析

    这题很多人一眼看过去是斜率DP。。。原谅本辣鸡没看不出来。。。但是推式子却推不出来,Claris还是你Claris,迷惑性很强。。。
    观察一下上面的代价式子,会发现是一个向量叉积的式子,两两之间选择的点求叉积,联系到三角剖分,可以知道最后的花费代价是所有点连起来的有向面积的和。
    如果斜率减小,则获得负面积,所以我们要沿着斜率减小的情况走。也就是维护一个上凸包。
    起点,终点,凸包上的拐点必须要选,重合的点只选字典序最小的一个,共线的点,则选择字典序最小的子序列
    解决重合的点可以考虑在读入点,排序后就预处理掉
    共线的点可以考虑贪心从右往左,如果当前结点序号比前一个选的共线的点还要小,则这个点也选取

    (题目要是没看错的话应该可以秒嘞。。。在想复杂了的情况下,思路已经很接近了。。。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    struct Point{
        long long x,y;
        int id;
        bool operator < (Point b) {return x<b.x || (x == b.x && y < b.y);}
        bool operator == (Point b){return x == b.x && y == b.y;}
        long long operator *(Point b){return x*b.y-y*b.x;}
        Point operator - (Point b){return Point{x-b.x,y-b.y,0};}
    }s[200005],a[200005];
    bool book[200005];
    int n,m;
    int solve()
    {
        int m = 0,k=1;
        s[m++] = a[n];
        for(int i = n-1;i>=1;i--)
        {
    	    while(m>k && (s[m-1]-s[m-2])*(a[i]-s[m-2])<0) m--;
    	    s[m++] = a[i];
        }
        m--;book[0] = book[m] = 1;
        for(int i = 1;i<m;i++) 
    	    if((s[i-1]-s[i])*(s[i]-s[i+1])) book[i] = 1;
        int pre;
        for(int i = 0;i<m;i++)
        	if(book[i] == 1) pre = i;
        	else{
    	        if(s[i].id<s[pre].id)
    		        book[i] = 1, pre = i;
        	}
        putchar('1');
        for(int i = m-1;i>=0;i--)
        {
        if(book[i]) printf(" %d",s[i].id);
        }
        putchar('
    ');
    
    
    }
    int main()
    {
        int _;scanf("%d",&_);
        while(_--)
        {
    	    memset(book,0,sizeof(book));
    	    scanf("%d",&n);
    	    for(int i = 1;i<=n;i++) 
    	        scanf("%lld%lld",&a[i].x,&a[i].y),a[i].id = i;
    	    sort(a+1,a+n+1);
    	    int now = 1;
    	    for(int i = 2;i<=n;i++)
    	    {
    	        if(a[i] == a[now]){
    	        	if(a[i].id < a[now].id)  a[now] = a[i];
    	        }
    	        else a[++now] = a[i];
    	    }
    	    n = now;
    	    solve();
        }
    }
    
  • 相关阅读:
    并发编程(四)—— ThreadLocal源码分析及内存泄露预防
    并发编程(三)—— ReentrantLock的用法
    并发编程(二)—— CountDownLatch、CyclicBarrier和Semaphore
    并发编程(一)—— volatile关键字和 atomic包
    Java 多线程(四)—— 单例模式
    Java 多线程(三)—— 线程的生命周期及方法
    Java 多线程(二)—— 线程的同步
    星空雅梦
    星空雅梦
    星空雅梦
  • 原文地址:https://www.cnblogs.com/greenty1208/p/9394336.html
Copyright © 2011-2022 走看看