bzoj3086: Coci2009 dvapravca

Description

给定平面上的 N 个点, 其中有一些是红的, 其他是蓝的.现在让你找两条平行的直线, 使得在保证
    不存在一个蓝色的点 被夹在两条平行线之间,不经过任何一个点, 不管是蓝色点还是红色点
的前提下, 被夹在平行线之间的红色点个数最多

Input

第1行: 一个整数 N (1 <= N <= 1000)
    第2..N+1行: 每行是一个点的坐标以及它的颜色.
                坐标用2个 绝对值<10^9 的整数表示
                颜色用 ‘R‘ 或 ‘B‘ 表示

Output

第1行: 仅一个整数, 被夹在平行线之间的红色点个数的最大值

令一条直线l垂直于所选平行直线,将点投影到直线上,考虑点的投影之间相对位置构成的序列,则问题转化为求序列的最长红色子串

直线旋转180度,则枚举了所有可能的倾斜角,而任意两点投影的相对位置只会发生一次变化,序列变化了O(n^2)次,因此可以用线段树维护这个序列同时维护最长红色子串

只能在序列上的投影点不发生重合时更新答案

#include<cstdio>
#include<algorithm>
typedef long long i64;
int n,ep=0,ans=0;
struct pos{
    int x,y;
};
pos operator-(pos a,pos b){
    return (pos){a.x-b.x,a.y-b.y};
}
i64 operator*(pos a,pos b){
    return i64(a.x)*b.y-i64(a.y)*b.x;
}
struct point{
    pos a;
    int col;
    bool operator<(const point&w)const{return a.y!=w.a.y?a.y<w.a.y:a.x<w.a.x;}
}ps[1007];
struct ev{
    pos x;
    int a,b;
    bool operator<(const ev&w)const{return x*w.x<0;}
}es[1007*507];
char str[4];
int ls[2111],rs[2111],ms[2111],ws[2111],sz[2111];
int max(int a,int b){return a>b?a:b;}
inline void up(int w,int l,int r){
    ms[w]=max(ms[l],max(ms[r],rs[l]+ls[r]));
    ls[w]=ls[l];
    if(ls[l]==sz[l])ls[w]+=ls[r];
    rs[w]=rs[r];
    if(rs[r]==sz[r])rs[w]+=rs[l];
}
void set(int w,int v){
    for(w+=1023,ls[w]=rs[w]=ms[w]=v,w>>=1;w;w>>=1)up(w,w<<1,w<<1^1);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d%d%s",&ps[i].a.x,&ps[i].a.y,str);
        ps[i].col=str[0]==‘R‘;
    }
    std::sort(ps+1,ps+n+1);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            pos w=ps[j].a-ps[i].a;
            if(w.y>0||w.y==0&&w.x>0)es[ep++]=(ev){w,i,j};
        }
    }
    for(int i=1;i<=n;++i){
        ws[i]=i;
        sz[i+1023]=1;
        if(ps[i].col)ls[i+1023]=rs[i+1023]=ms[i+1023]=1;
    }
    for(int i=1023;i;--i)sz[i]=sz[i<<1]+sz[i<<1^1],up(i,i<<1,i<<1^1);
    ans=ms[1];
    std::sort(es,es+ep);
    for(int i=0,j=0;i<ep;){
        for(;j<ep&&es[i].x*es[j].x==0;++j);
        for(;i<j;++i){
            int a=es[i].a,b=es[i].b;
            std::swap(ws[a],ws[b]);
            if(ps[a].col!=ps[b].col){
                set(ws[a],ps[a].col);
                set(ws[b],ps[b].col);
            }
        }
        ans=max(ans,ms[1]);
    }
    printf("%d",ans);
    return 0;
}
时间: 2024-10-13 23:17:39

bzoj3086: Coci2009 dvapravca的相关文章

bzoj3087: Coci2009 misolovke

Description [misolovke]给定一个 N*N 的网格.每个格子里至少会有一个捕鼠器, 并且已知每个格子里的捕鼠器个数.现在需要在 每一行 中选取恰好 K 个连续的格子, 把里面的捕鼠器全部拿走, 并且需要满足 老鼠不能 从网格最左边到网格最右边 也不能 从网格最上面到网格最下面 老鼠行走的方向是 上下左右 4个方向 老鼠只能经过没有捕鼠器的格子求拿走捕鼠器个数的最大值 Input 第1行: 2 个整数 N, K (2 <= N <= 250, 1 <= K <=

COCI2009 PATULJCI

给出N个人的颜色,有c种不同的颜色.给出查询次数M查找区间[L,R],对于每次查询操作,问在区间[L,R]是否有有一种颜色的出现的次数>(L+R)/2,如果有,输出yes及颜色的种类,否则输出no. 暴搜大概能过3个点.我的最先思路是对于每种颜色都求一个前缀和,然后每次的查询操作时间复杂度就是O(1),但是光是为了记录颜色的颜色和就已经超时了,而且还要暴内存,于是我们不得不寻求更简便的方法. 每种颜色我们可以按大小排序,大小相同的按出现位置排序,并记录下每一个颜色的出现的位置,保存在一个数组里边

BZOJ2223:[Coci2009]PATULJCI——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2223 Description Sample Input 10 3 1 2 1 2 1 2 3 2 3 3 8 1 2 1 3 1 4 1 5 2 5 2 6 6 9 7 10 Sample Output no yes 1 no yes 1 no yes 2 no yes 3 HINT Notice:输入第二个整数是序列中权值的范围Lim,即1<=ai(1<=i<=n)<=Lim. 1

[Luogu5181][COCI2009]GENIJALAC

题目链接: Luogu5181 一个简单题? 首先对\([C+1,n-D]\)中的每个数字求出循环节,求\(Lcm\)即是整段的循环节. 然后判断\([A,B]\)中有几个数满足\(x-1\equiv 0(mod\ Lcm)\). 求循环节暴力可过.. 其实求循环节是可以\(O(n)\)的. 每一次求循环节得到一个环,那么环上所有点的循环节都是此次求出的循环节. 那么就可以\(O(n)\)得到所有循环节. 代码: #include <cstdio> #include <cstdlib&g

【2019.10.18】luogu TG5动态规划进阶

树形dp P1352 没有上司的舞会 P2607 骑士(review) 对于每一个"联通快" 只有根节点有机会形成环 强制不选\(rt\)和\(rt\)的父亲 各跑一遍 P1131 时态同步(review) 贪心 显然增加深度约小的边越优 从下到上来调整 先将同一个点的儿子们延伸到一样 再往上进行一样的操作 //apio 烟火 树上背包? 一棵\(n\)个点的树,有点权.选择一个大小不超过\(K\)的联通块,使得点权和最大.\(n ≤ 2000\) \(f(x, i)\)表示\(x\)