[bzoj]2131: 免费的馅饼

Posted onglublog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj]2131: 免费的馅饼相关的知识,希望对你有一定的参考价值。

原题链接:免费的馅饼

题意

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

问最多接到的饼子价值。

分析

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

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

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

我们可以旋转坐标系,让$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 nodedouble 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\n",ans);
    return 0;

/*
建立坐标系,发现每次移动都是45度角
旋转坐标系变为45度角,求最长不下降子序列即可 
虽然带权,但是点权很小,直接把一个点拆成点权个数个点 
  
*/ 
View Code

 

以上是关于[bzoj]2131: 免费的馅饼的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2131: 免费的馅饼

bzoj2131免费的馅饼 dp+树状数组

bzoj2131: 免费的馅饼

BZOJ 2131 免费的馅饼(DP,二维偏序问题 / 旋转坐标轴转化问题)BZOJ 修复工程

BZOJ 2131 免费的馅饼(DP,二维偏序问题 / 旋转坐标轴转化问题)BZOJ 修复工程

免费的馅饼 HYSBZ - 2131 (树状数组维护二维偏序)