peiwenjun's blog 没有知识的荒原

ICPC2021上海 CF103446A Strange Functions 题解

题目描述

给定 \(n\) 个函数:

\[f_i(x)=\begin{cases} |\arctan(k_i\sec(x-a_i))|&(x\neq a_i+(k+\frac12)\pi,k\in\Z)\\ \frac\pi2&(x=a_i+(k+\frac12)\pi,k\in\Z) \end{cases} \]

求每个函数是否可能作为最小值出现,即 \(\forall1\le i\le n\) ,求是否存在 \(x\) ,满足 \(\forall j\neq i,f_i(x)\lt f_j(x)\) 。

数据范围

  • \(1\le n\le 10^5,1\le k_i,|a_i|\le 10^5\) ,保证不存在两个完全相同的函数。

时间限制 \(\texttt{2s}\),空间限制 \(\texttt{256MB}\) 。

分析

注意到 \(\arctan x\) 为奇函数且单调递增,因此我们只需要关心 \(|k_i\sec(x-a_i)|\) 的大小关系。

image

如图,记 \(\angle AOD=a_i,\angle AOC_1=x,|OD|=k_i\) ,则\(|OC_1|=k_i\sec(x-a_i)\)。

特别地,如果 \(\angle COD\) 为钝角,那么交点 \(C_2\) 会落在直线 \(BE\) 上。

第 \(i\) 个函数会贡献 \(AD,BE\) 两条直线,而 \(f_i(x)\) 的最小值,就是过原点且倾角为 \(x\) 的直线(\(OC_1\))上,离原点最近的那一个。

求一遍半平面交,凸包上所有边对应的 \(f_i(x)\) 就是所有可能成为最小值的函数。

时间复杂度 \(\mathcal O(n\log n)\) 。

#include<bits/stdc++.h>
#define double long double
#define fi first
#define se second
#define mp make_pair
#define pdd pair<double,double>
using namespace std;
const int maxn=2e5+5;
const double eps=1e-10;
int a,k,m,n;
pdd p[maxn];
int q[maxn];
bool vis[maxn];
struct line
{
    pdd st,ed;
    int id;
}f[maxn];
pdd operator+(pdd a,pdd b)
{
    return mp(a.fi+b.fi,a.se+b.se);
}
pdd operator-(pdd a,pdd b)
{
    return mp(a.fi-b.fi,a.se-b.se);
}
pdd operator*(pdd a,double b)
{
    return mp(a.fi*b,a.se*b);
}
int sign(double x)
{
    if(fabs(x)<=eps) return 0;
    return x>0?1:-1;
}
double cross(pdd a,pdd b)
{
    return a.fi*b.se-a.se*b.fi;
}
double area(pdd a,pdd b,pdd c)
{
    return cross(b-a,c-a);
}
double get_angle(line p)
{
    return atan2(p.ed.se-p.st.se,p.ed.fi-p.st.fi);
}
bool cmp(line a,line b)
{
    double x=get_angle(a),y=get_angle(b);
    if(sign(x-y)) return x<y;
    return sign(area(a.st,b.st,a.ed))==1;
}
pdd intersect(line a,line b)
{
    double s1=area(a.st,b.st,a.ed),s2=area(a.st,a.ed,b.ed);
    return b.st+(b.ed-b.st)*(s1/(s1+s2));
}
bool on_right(line a,line b,line c)
{
    return sign(area(a.st,a.ed,intersect(b,c)))<=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&k,&a);
        f[++m]={mp(k*cos(a),k*sin(a)),mp(k*cos(a),k*sin(a))+mp(-sin(a),cos(a)),i};
        f[m+1]={f[m].st*-1,f[m].ed*-1,i},m++;
    }
    sort(f+1,f+m+1,cmp);
    int h=1,t=0;
    for(int i=1;i<=m;i++)
    {
        if(i>=2&&!sign(get_angle(f[i])-get_angle(f[i-1]))) continue;
        while(h<t&&on_right(f[i],f[q[t-1]],f[q[t]])) t--;
        while(h<t&&on_right(f[i],f[q[h]],f[q[h+1]])) h++;
        q[++t]=i;
    }
    while(h<t&&on_right(f[q[h]],f[q[t-1]],f[q[t]])) t--;
    for(int i=h;i<=t;i++) vis[f[q[i]].id]=true;
    for(int i=1;i<=n;i++) putchar(vis[i]+'0');
    putchar('\n');
    return 0;
}

posted on 2023-04-25 19:31  peiwenjun  阅读(13)  评论(0)    收藏  举报

导航