【凸包】【KMP】Codeforces1017E The Supersonic Rocket

7 篇文章 0 订阅
6 篇文章 0 订阅

分析:

。。。第一次见CF服务器炸了,还好最后unrated了,不然这次死惨。。。

很容易想到,这两个多边形的凸包能通过旋转、平移最终重合,就必然满足条件。

所以就是判断两多边形是否全等。

额。。题解就是标题:顺时针地把两个凸包每个边的长度、每个点的旋转角储存下来(长度不开根号,旋转角用差积表示,这样都是整数)。

如果这两个序列能完全匹配,则说明能够重合。方法就是把其中一个串复制一遍粘在后面,然后在另一个序列上建KMP,然后依次匹配,看能否匹配到末尾。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 400010
#define EPS 1e-7
using namespace std;
typedef long long ll;
const double Pi=acos(-1);
struct node{
    ll x,y;
    node(){}
    node(ll xx,ll yy):x(xx),y(yy) {}
    node operator + (const node &a) const {
        return node(x+a.x,y+a.y);
    }
    node operator - (const node &a) const {
        return node(x-a.x,y-a.y);
    }
    node operator * (const double &t) const {
        return node(x*t,y*t);
    }
    double operator *(const node &a) const{
        return x*a.x+y*a.y;
    }
    double operator ^(const node &a) const{
        return x*a.y-y*a.x;
    }
    bool operator <(const node &a) const {
        return a.x!=x?x<a.x:y<a.y;
    }
};
bool cmp(node a,node b){
    return b<a;
}
class Curex{
    public:
    node p[MAXN],l1[MAXN];
    stack<node> s1,s;
    ll ans[MAXN];
    int n,cnt1,cnt2;
    void solve(node a1[],int &cnt){
        s.push(p[1]);
        s1.push(p[1]);
        s1.push(p[2]);
        for(int i=3;i<=n;i++){
            while(!s.empty()&&((p[i]-s.top())^(s1.top()-s.top()))<=0){
                s.pop();
                s1.pop();
            }
            s.push(s1.top());
            s1.push(p[i]);
        }
        while(!s1.empty()){
            a1[++cnt]=s1.top();
            s1.pop();
        }
        while(!s.empty())
            s.pop();
    }
    void init(int n1){
        n=n1;
        for(int i=1;i<=n;i++)
            SF("%I64d%I64d",&p[i].x,&p[i].y);
        sort(p+1,p+1+n);
        solve(l1,cnt1);
        sort(p+1,p+1+n,cmp);
        cnt1--;
        solve(l1,cnt1);
        cnt1--;
        cnt2=0;
        for(int i=1;i<=cnt1;i++){
            int las,nxt;
            if(i==1)
                las=cnt1;
            else
                las=i-1;
            if(i==cnt1)
                nxt=1;
            else
                nxt=i+1;
            ans[++cnt2]=(ll)((l1[nxt]-l1[i])*(l1[las]-l1[i]));
            ll xx=(l1[nxt]-l1[i]).x;
            ll yy=(l1[nxt]-l1[i]).y;
            ans[++cnt2]=xx*xx+yy*yy;
        }   
    }
}fir,sec;
int las[MAXN];
void build(ll a[]){
    int len=fir.cnt2;
    for(int i=0;i<len;i++){
        int x=i;
        while(x){
            x=las[x];
            if(a[x+1]==a[i+1]){
                las[i+1]=x+1;
                break;
            }
        }
    }
}
bool check(int n,ll a[],int m,ll b[]){
    int lasx=0;
    for(int i=1;i<=m;i++){
        while(lasx&&a[lasx+1]!=b[i])
            lasx=las[lasx];
        if(a[lasx+1]==b[i])
            lasx++;
        if(lasx==n)
            return 1;
    }
    return 0;
}
int main(){
    int n,m;
    SF("%d%d",&n,&m);
    fir.init(n);
    sec.init(m);
    if(fir.cnt1!=sec.cnt1){
        PF("NO");
        return 0;
    }
    build(fir.ans);
    for(int i=1;i<=sec.cnt2;i++)
        sec.ans[sec.cnt2+i]=sec.ans[i];
    sec.cnt2*=2;
    if(check(fir.cnt2,fir.ans,sec.cnt2,sec.ans))
        PF("YES\n");
    else
        PF("NO\n");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值