[COCI2009]Dvapravca

本文介绍了一种算法,用于解决在平面内找到一对平行线的问题,使夹在它们之间的红色点数量最多,同时确保平行线间无蓝色点且不经过任何点。通过将点投影到垂直线上并使用线段树维护最长全红子串来实现。

题意

给定平面上的 N N 个点,其中有一些是红的 , , 其他是蓝的

现在让你找一对平行线,在满足在平行线之间没有蓝点 , , 并且平行线不经过任何一个点的情况下,使得被夹在平行线之间的红色点个数最多

给出的点没有三点共线的情况 , , 平行线可以不平行坐标轴


题解

做一条垂直于平行线的线,然后把所有点排序后都投影到这条线上形成一个序列

那么考虑在序列上我们要求的就是最长全红子串了

这个可以用线段树直接维护 ; ; 考虑到平行线的角度会变

那么答案就是我们把这条垂线在旋转180的过程中所有投影序列的答案的最大值

我们显然不能直接去旋转 , , 考虑要怎么样投影序列才会发生变化

这里写图片描述

投影序列是{1,2,3,4},那么颜色序列就是 1001, 1001 , 答案是 1 1

这里写图片描述

当投影线是L1时投影序列是 {1,2,3,4} { 1 , 2 , 3 , 4 }

当投影线是 L2 L 2 时投影序列是 {1,2,4,3} { 1 , 2 , 4 , 3 }

也就是说当投影线的斜率从小于两点连线垂线 (Lx) ( L x ) 斜率到大于他的过程中这两个点在投影序列上的位置会互换

因为垂线的斜率和原直线的斜率是一一对应的 , , 那么我们可以直接按照两点之间的连线的斜率排序

那么旋转投影线每次就可以直接旋转到下一个垂线的位置

即使有两点投影位置相同也没关系,因为我们可以微调一下

注意对于所有斜率相同的直线我们需要一次性在线段树上处理完

因为总共有 n2 n 2 条线 , , 所以会发生n2次交换 , , 所以复杂度是O(n2logn)

Hint: H i n t :

连线的方向和转动的方向要一致(需要脑补一下)

斜率判等的精度要高一点

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=1005,M=5e5+5;
const double eps=1e-15;
typedef int arr[N];
typedef double db;
struct po{
    int x,y,col,id;
    inline void in(){sd(x),sd(y),col=gc()=='R';}
    inline bool operator<(const po b)const{return x==b.x?y<b.y:x<b.x;}
    inline db operator/(const po b){return atan2(y-b.y,x-b.x);}
}p[N];
struct Li{
    int a,b;db slope;
    inline bool operator<(const Li T)const{return slope<T.slope;}
    inline bool operator==(const Li b)const{return fabs(slope-b.slope)<eps;}
}L[M];
struct Seg{int l,r,mx,sz;}tr[N<<2];
int n,m,ans,Sz=1;
inline void up(int p,int lc,int rc){
    tr[p].mx=max(tr[lc].r+tr[rc].l,max(tr[lc].mx,tr[rc].mx));
    tr[p].l=tr[lc].l,tr[p].r=tr[rc].r;
    if(tr[lc].l==tr[lc].sz)tr[p].l+=tr[rc].l;
    if(tr[rc].r==tr[rc].sz)tr[p].r+=tr[lc].r;
}
inline void mdy(int p,int x){for(p+=Sz,tr[p]={x,x,x,1},p>>=1;p;p>>=1)up(p,p<<1,p<<1|1);}
inline void upd(Li x){
    if(p[x.a].col^p[x.b].col)
        mdy(p[x.b].id,p[x.a].col),
        mdy(p[x.a].id,p[x.b].col);
    swap(p[x.a].id,p[x.b].id);
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n);
    fp(i,1,n)p[i].in();sort(p+1,p+n+1);
    fp(i,1,n)p[i].id=i;while(Sz<=n)Sz<<=1;--Sz;
    fp(i,1,n)tr[i+Sz].sz=1,p[i].col?tr[i+Sz]={1,1,1,1},1:0;
    fd(i,Sz,1)tr[i].sz=tr[i<<1].sz+tr[i<<1|1].sz,up(i,i<<1,i<<1|1);
    fp(i,1,n)fp(j,i+1,n)L[++m]={i,j,p[j]/p[i]};
    sort(L+1,L+m+1);
    fp(i,1,m){
        upd(L[i]);
        while(L[i]==L[i+1]&&i<m)upd(L[++i]);
        cmax(ans,tr[1].mx);
    }
    printf("%d\n",ans);
return 0;
}
基于STM32 F4的永磁同步电机无位置传感器控制策略研究内容概要:本文围绕基于STM32 F4的永磁同步电机(PMSM)无位置传感器控制策略展开研究,重点探讨在不依赖物理位置传感器的情况下,如何通过算法实现对电机转子位置和速度的精确估计与控制。文中结合嵌入式开发平台STM32 F4,采用如滑模观测器、扩展卡尔曼滤波或高频注入法等先进观测技术,实现对电机反电动势或磁链的估算,进而完成无传感器矢量控制(FOC)。同时,研究涵盖系统建模、控制算法设计、仿真验证(可能使用Simulink)以及在STM32硬件平台上的代码实现与调试,旨在提高电机控制系统的可靠性、降低成本并增强环境适应性。; 适合人群:具备一定电力电子、自动控制理论基础和嵌入式开发经验的电气工程、自动化及相关专业的研究生、科研人员及从事电机驱动开发的工程师。; 使用场景及目标:①掌握永磁同步电机无位置传感器控制的核心原理与实现方法;②学习如何在STM32平台上进行电机控制算法的移植与优化;③为开发高性能、低成本的电机驱动系统提供技术参考与实践指导。; 阅读建议:建议读者结合文中提到的控制理论、仿真模型与实际代码实现进行系统学习,有条件者应在实验平台上进行验证,重点关注观测器设计、参数整定及系统稳定性分析等关键环节。
### 解题思路 COCI 2008-2009 Contest 4 中的 **PERIODNI** 问题是关于构建具有特定周期性质的字符串的问题。题目要求找到一个长度为 $ N $ 的字符串,使得字符串中每个位置的字符满足周期性条件。具体来说,对于给定的 $ K $ 个周期条件 $ d_1, d_2, \dots, d_K $,需要保证字符串中任意两个字符 $ s[i] $ 和 $ s[i + d_j] $ 相等(其中 $ i + d_j \leq N $)。 解决这个问题的关键在于使用 **并查集(Union-Find)** 数据结构来管理字符的等价类。每个字符位置的约束条件可以通过并查集将相关位置合并,从而确保最终字符串满足所有周期条件。 #### 主要步骤: 1. **初始化并查集**:创建一个大小为 $ N+1 $ 的并查集,用于管理字符串中每个位置的等价类。 2. **处理周期条件**:对于每个周期 $ d_j $,将所有满足 $ i + d_j \leq N $ 的位置 $ i $ 和 $ i + d_j $ 合并到同一个等价类中。 3. **统计独立字符数量**:计算并查集中独立的等价类数量,每个等价类可以分配一个唯一的字符。 4. **计算结果**:由于每个等价类可以使用字母表中的任意一个字符,因此结果为字母表大小的等价类数量次幂。 #### 代码示例 以下是一个基于并查集的解法实现: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 5; int parent[MAXN]; int find(int x) { if (parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } void unite(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) parent[rootY] = rootX; } int main() { int N, K; cin >> N >> K; // 初始化并查集 for (int i = 1; i <= N; i++) parent[i] = i; for (int k = 0; k < K; k++) { int d; cin >> d; for (int i = 1; i + d <= N; i++) { unite(i, i + d); } } // 统计独立的等价类数量 unordered_set<int> uniqueRoots; for (int i = 1; i <= N; i++) { uniqueRoots.insert(find(i)); } // 输出结果 cout << uniqueRoots.size() << endl; return 0; } ``` ### 关键点说明 1. **并查集的应用**:通过并查集将满足周期条件的位置合并,从而确保字符串中字符的周期性约束。 2. **复杂度分析**:时间复杂度主要由并查集操作决定,约为 $ O(N \cdot \alpha(N)) $,其中 $ \alpha(N) $ 是阿克曼函数的反函数,增长极慢。 3. **扩展性**:该解法可以轻松扩展到处理更复杂的周期约束条件。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值