LOJ

思路

显然多边形旋转可以变成点旋转,不同的点的贡献可以分开计算。

然后就变成了要求一个圆在多边形内的弧长。

考虑把交点全都求出来,那么两个交点之间的状态显然是相同的,可以直接把圆弧上的中点的状态求出来。

求圆弧上的中点也要特判两个向量恰好相反,或是转的角度大于\(\pi\)。

然后求交点……求出和直线的交点再判一下在线段上即可。

然而……有一种较为恶心的情况:没有交点或是只有一个交点,此时可能圆把多边形包住了,也可能是被包住了。

判一下这个点随机转某个角度后是否在多边形内即可。

还要特判\((0,0)\),因为不管有没有交点你都求不出角度。

判断是否在多边形内也可以用随机斜率的方法避免边界情况,只要这个点自己不在多边形上。

算角度的时候还要稍微搞一搞,否则会因为精度的问题让\(\text{acos}\)函数返回nan

(有各种垃圾细节,我用各种方法叉掉的代码都可以AC)

附几个能把我原来的代码叉掉的数据:

1 5
1 0
2 0
3 0
0 7
-7 0
0 -7
1 6
-1 0
-2 0
-1 0
-1 -2
2 -2
2 2
-2 2
1 4
0 0
0 0
1 0
1 1
0 1

代码

如果能找到把我叉掉的数据还请在评论里踩我,谢谢/kel

update:经ntf提醒,我自己的hack数据就可以hack我自己……代码已更新……

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 666
typedef long long ll;
typedef long double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifdef NTFOrz
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; int n,m; #define eps 1e-7
const db pi=acos(-1);
db dcmp(db x){return fabs(x)>eps?(x>0?1:-1):0;}
struct Point
{
db x,y;
Point(db X=0,db Y=0){x=X,y=Y;}
const Point operator + (const Point &a) const {return Point(x+a.x,y+a.y);}
const Point operator - (const Point &a) const {return Point(x-a.x,y-a.y);}
const Point operator * (const db &a) const {return Point(x*a,y*a);}
const Point operator / (const db &a) const {return Point(x/a,y/a);}
};
#define Vector Point
db Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
db Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
db Len(Vector a){return sqrt(Dot(a,a));}
db Len2(Vector a){return Dot(a,a);}
Vector One(Vector a){return a/Len(a);}
Vector Normal(Vector a){return Vector(-a.y,a.x);}
Point Mid(Point a,Point b)
{
if (!dcmp(Cross(a,b))) return Normal(b);
Point ret=(a+b)/2;ret=One(ret)*Len(a);
if (dcmp(Cross(a,b))<0) ret=ret*(-1);
return ret;
} struct Line
{
Point a,b;
Line(Point A,Point B){a=A,b=B;}
};
Point LI(Line l1,Line l2)
{
Vector v=l1.a-l2.a,v1=l1.b-l1.a,v2=l2.b-l2.a;
db t=Cross(v,v2)/Cross(v2,v1);
return l1.a+v1*t;
}
bool OnSeg(Line s,Point p){return dcmp(Dot(p-s.a,p-s.b))<=0;}
db DisL(Line l,Point p){return fabs(Cross(p-l.a,l.b-l.a)/Len(l.b-l.a));} Point q[sz];
Point poly[sz];
Point tmp[sz<<1],tmp1[sz<<1];int K,KK; bool In(Point p)
{
Line l(p,p+Point(cos(233),sin(666))*1e8);
bool ret=0;
rep(i,1,m)
{
Point it=LI(Line(poly[i],poly[i+1]),l);
ret^=OnSeg(Line(poly[i],poly[i+1]),it)&&OnSeg(l,it);
}
return ret;
}
void Work(Point p,Line s)
{
db len=Len(p);
Vector norm=Normal(s.a-s.b);
Point it=LI(Line(Point(0,0),norm),s);
if (dcmp(Len(it)-len)>0) return;
db l=sqrt(Len2(p)-Len2(it));
Point p1=it+One(s.a-s.b)*l,p2=it-One(s.a-s.b)*l;
if (OnSeg(s,p1)) tmp[++K]=p1;
if (OnSeg(s,p2)) tmp[++K]=p2;
} int main()
{
file();
read(n,m);
rep(i,1,n) read(q[i].x,q[i].y);
rep(i,1,m) read(poly[i].x,poly[i].y);
poly[m+1]=poly[1];
db ans=0;
rep(i,1,n)
{
if (!dcmp(Len(q[i]))) { ans+=In(Vector(0,0)); continue; }
K=0;
rep(j,1,m) Work(q[i],Line(poly[j],poly[j+1]));
sort(tmp+1,tmp+K+1,[](const Point &x,const Point &y){return atan2(x.y,x.x)<atan2(y.y,y.x);});
tmp1[KK=1]=tmp[1];rep(i,2,K) if (dcmp(Len(tmp[i]-tmp[i-1]))) tmp1[++KK]=tmp[i];
tmp1[KK+1]=tmp1[1];
if (KK<=1) { ans+=In(One(Vector(sin(233),cos(666)))*Len(q[i])); continue; }
rep(j,1,KK) if (In(Mid(tmp1[j],tmp1[j+1])))
{
db cur,p;
p=Dot(tmp1[j],tmp1[j+1])/Len(tmp1[j])/Len(tmp1[j+1]);
chkmin(p,(db)1),chkmax(p,-(db)1);
cur=acos(p);
if (dcmp(Cross(tmp1[j],tmp1[j+1]))<0) cur=pi+pi-cur;
ans+=cur/2/pi;
}
}
cout<<setprecision(5)<<fixed<<ans<<'\n';
return 0;
}

LOJ6437. 「PKUSC2018」PKUSC [计算几何]的更多相关文章

  1. [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC

    [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC 试题描述 九条可怜是一个爱玩游戏的女孩子. 最近她在玩一个无双割草类的游戏,平面上有 \(n\) 个敌人,每一个敌人的坐标为 ...

  2. loj#6437. 「PKUSC2018」PKUSC(计算几何)

    题面 传送门 题解 计算几何的东西我好像都已经忘光了-- 首先我们可以把原问题转化为另一个等价的问题:对于每一个敌人,我们以原点为圆心,画一个经过该点的圆,把这个圆在多边形内部的圆弧的度数加入答案.求 ...

  3. 【LOJ】#6437. 「PKUSC2018」PKUSC

    题解 我们把这个多边形三角形剖分了,和统计多边形面积一样 每个三角形有个点是原点,把原点所对应的角度算出来,记为theta 对于一个点,相当于半径为这个点到原点的一个圆,圆弧上的弧度为theta的一部 ...

  4. 「PKUSC2018」PKUSC

    传送门 Solution  考虑求每个点的贡献 等价于一个以OA长为半径的圆心为原点的圆在多边形内的弧对应的角度/\(2\pi\) 求弧度可以利用三角剖分 在原点的点要特判,采用射线法就可以了 Cod ...

  5. LOJ#6437. 「PKUSC2018」PKUSC

    题面 题意转化为: 判断每个点所在的圆有多长的弧度角位于多边形内部. 然后就很暴力了. 每个点P,直接找到多边形和这个圆的所有交点,按照距离P的角度排序. 找交点,直接联立二元二次方程组.... 需要 ...

  6. LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

  7. LOJ #6435. 「PKUSC2018」星际穿越(倍增)

    题面 LOJ#6435. 「PKUSC2018」星际穿越 题解 参考了 这位大佬的博客 这道题好恶心啊qwq~~ 首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条 ...

  8. LOJ #6432. 「PKUSC2018」真实排名(组合数)

    题面 LOJ #6432. 「PKUSC2018」真实排名 注意排名的定义 , 分数不小于他的选手数量 !!! 题解 有点坑的细节题 ... 思路很简单 , 把每个数分两种情况讨论一下了 . 假设它为 ...

  9. 【loj6437】 【PKUSC2018】 PKUSC 计算几何

    题目大意:给你一个m个点的简单多边形.对于每个点i∈[1,n],作一个以O点为原点且过点i的圆,求该圆在多边形内的圆弧长度/圆长. 其中n≤200,m≤500. 我们将n个点分开处理. 首先,我们要判 ...

随机推荐

  1. Ambari调整日志级别:How to enable debug logging in Ambari Server and Ambari Agent ?

    PURPOSE When troubleshooting Ambari issues, it may be necessary to enable debug logging in the Ambar ...

  2. 3.使用 Code First 迁移更新数据库

    1.更新 SeedData 类,使它提供新列的值. 示例更改如下所示,但可能需要对每个 new Movie 块做出此更改. context.Movie.AddRange( new Movie { Ti ...

  3. c#利用定时器自动备份数据库(mysql)

    1:引用dll MySql.Data.dll,   MySqlbackup.dll 2:建一个数据连接静态类 public static class mysql{public static strin ...

  4. 1 matplotlib绘制折线图

    from matplotlib import pyplot as plt #设置图形大小 plt.figure(figsize=(20,8),dpi=80) plt.plot(x,y,color=&q ...

  5. Python的字符串函数

    今天用了将近一天的时间去学习Python字符串函数 上午学了17个,下午学了23个(共计40) 详细内容请见菜鸟教程--Python3字符串--Python的字符串内建函数

  6. 30个关于Shell脚本的经典案例(中)

    本文目录 11.iptables自动屏蔽访问网站频繁的IP 12.判断用户输入的是否为IP地址 13.判断用户输入的是否为数字 14.给定目录找出包含关键字的文件 15.监控目录,将新创建的文件名追加 ...

  7. Mac音频播放

    Mac音频播放 audioqueue播放pcm数据 http://msching.github.io/blog/2014/08/02/audio-in-ios-5/ audiounit播放pcm数据  ...

  8. tomcat 安装记录 centos7 开放对外端口

    //端口查询 [root@CentOS7 bin]# firewall-cmd --query-port=9090/tcp no //添加端口 [root@CentOS7 bin]# firewall ...

  9. Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the

    参考链接 解决方法: 修改 php.ini  : always_populate_raw_post_data = -1 PHP 5.6已经废弃了$HTTP_RAW_POST_DATA

  10. 自动化测试常用断言的使用方法(python+selenium)

    自动化测试常用断言的使用方法(python) 自动化测试中寻找元素并进行操作,如果在元素好找的情况下,相信大家都可以较熟练地编写用例脚本了,但光进行操作可能还不够,有时候也需要对预期结果进行判断. 这 ...