• [bzoj]2131: 免费的馅饼


    原题链接:免费的馅饼

    题意

    接饼子游戏,饼子每秒下落一格,然后人每秒可以向左或者向右移动一格或者两格,当然也可以原地不动。

    问最多接到的饼子价值。

    分析

    发现网上的做法都是dp+树状数组优化的。

    这里提供一个另外的思路。

    由于每秒向左向右移动的步数可以是$0,1,2$步,转化在坐标系中可以是一个夹角,右边界的斜率$k=frac{sqrt{5}}{5}$。

    我们可以旋转坐标系,让$x$轴和右边界对齐,然后再旋转$y$轴,把原坐标系变为一个斜坐标系,这样子我们接完每个饼之后只能向$x,y$的正方向移动。

    然后按照横坐标排序之后就变成一个求一个带权$LIS$的问题了。

    怎么处理带权$LIS$呢,拆点,每个权值为$v_i$的点拆成$v_i$个点,这样就不带权了,然后求个$LIS$就行了。

    但是这里的$n*v_i$是$10^8$还需要一步优化。

    我们开一个$double->int$的$std::map$,按照$nlogn$的$LIS$算法,每次插入一个值就查找后继,删除掉跟插入一样多的后继,如果后继不够说明答案增加。

    把全部点都插完之后直接遍历$std::map$然后把所有的权值累加就行了

    代码

    #include <bits/stdc++.h>
    #define ll long long
    #define Mid ((l+r)>>1)
    #define ull unsigned long long
    using namespace std;
    const double Pi=acos(1.0);
    int read(){
        char c;int num,f=1;
        while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
        while(c=getchar(), isdigit(c))num=num*10+c-'0';
        return f*num;
    }
    const int N=1e5+1009;
    struct node{double x,y;int w;}a[N];
    map<double,int>g; 
    map<double,int>::iterator it,it2;
    int n,w;
    double Sin,Cos,Sin2,Cos2;
    bool cmp(node a,node b){return a.x<b.x;}
    int main()
    {
        Sin=1.0/sqrt(5);
        Cos=2.0/sqrt(5);
        Sin2=2*Cos*Cos-1; 
        Cos2=2*Sin*Cos;
        w=read();n=read();
        for(int i=1;i<=n;i++){
            double y=read(),x=read(),p;
            a[i].w=read();
            a[i].x=Cos*x+Sin*y;a[i].y=Cos*y-Sin*x;
            //先把坐标系旋转到x轴与k=1/sqrt(5)相同 
            x=a[i].x;y=a[i].y;
            a[i].x=x+y*Sin2/Cos2;a[i].y=y/Cos2;
            //再把直角坐标系映射到斜坐标系 
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++){
            int t=a[i].w;
            if(g.find(a[i].y)!=g.end())g[a[i].y]+=t;
            else g[a[i].y]=t;
            it=++g.find(a[i].y);
            while(t&&it!=g.end()){
                if((it->second)<=t){
                    it2=it++;
                    t-=(it2->second);
                    g.erase(it2);
                }else{
                    (it->second)-=t;
                    t=0;
                } 
            }
            
        }
        int ans=0;
        for(it=g.begin();it!=g.end();it++)
            ans+=(it->second);
        printf("%d
    ",ans);
        return 0;
    }
    /*
    建立坐标系,发现每次移动都是45度角
    旋转坐标系变为45度角,求最长不下降子序列即可 
    虽然带权,但是点权很小,直接把一个点拆成点权个数个点 
      
    */ 
    View Code
  • 相关阅读:
    HTML语言基础
    过滤器Filter
    新闻实现分页显示
    [转]Jmeter使用入门
    [转]ZK工作原理
    [转]UT-IT-ST-BBIT-SDV-SIT-SVT
    Unix编码哲学
    火星坐标、百度坐标、WGS-84坐标相互转换及墨卡托投影坐标转经纬度JavaScript版
    递归公用表表达式概述
    java写word转pdf
  • 原文地址:https://www.cnblogs.com/onglublog/p/11325459.html
Copyright © 2020-2023  润新知