互测六 题解 9.18 圆润的多边形&Takuji与信徒

圆润的多边形:

我们可将所求图形划分如下:

绿色部分是一凸多边形,红色部分为若干个长方形,蓝色部分为若干个扇形。

易证:1.蓝色部分的总和是一个半径为r的整圆;2.红色部分的总和=凸多边形周长*r。

那么现在就只剩下如何计算的问题。

1.对于前12.5%数据,r=0且点坐标成顺时针排列,那么直接作为凸多边形来计算即可;

2.对于前50%数据,点坐标成顺时针排列,这个部分分的做法。。。我也没想出来。。。

这是为什么呢。。。因为这个题,是我受了洛谷P1513的启发而脑补出来的,这道题中有“点坐标成顺时针排列”的限制,所以我一激动就搞出了这么个自己都不知咋做的部分分。。。见谅见谅。。。

3.对于100%的数据:

终于进入正题了。

我们先将目标放在内部的凸多边形上。

点坐标无序,如何找到一种能算的形式呢?解决方案是排序。

具体排序方法:按y坐标为第一关键字,x坐标为第二关键字,从小到大排序。

排完之后的计算方法:

1.在排序后的序列中找到第一个点和第n个点,计算一下过此两点的直线方程;

2.扫描第2~n-1个点,判断当前点与先前直线的位置关系,若在直线左侧则压入一个数组,记为l[],在右侧则压入另一数组,记为r[];

3.对{第一个点,第n个点,l[]},{第一个点,第n个点,r[]}分别计算周长和面积,最后相加即可。细节请见代码。

然后,蓝色部分=πr^2,红色部分=周长*r,将这三个值相加即得最终结果。

标程:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<ctime>
  6 #include<cstdlib>
  7
  8 #include<string>
  9 #include<stack>
 10 #include<queue>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<map>
 14 #include<set>
 15
 16 using namespace std;
 17
 18 double pi=acos(-1);
 19
 20 struct points{
 21     double x,y;
 22 };
 23
 24 bool cmp(points aa,points bb){
 25     if(aa.y!=bb.y)return aa.y<bb.y;
 26     else return aa.x<bb.x;
 27 }
 28
 29 double getd(points aa,points bb){
 30     return sqrt(pow((aa.x-bb.x),2)+pow((aa.y-bb.y),2));
 31 }
 32
 33 double getv(points aa,points bb,points cc){
 34     double d1=getd(aa,bb);
 35     double d2=getd(bb,cc);
 36     double d3=getd(cc,aa);
 37
 38     double p=(d1+d2+d3)/2;
 39
 40     return sqrt(p*(p-d1)*(p-d2)*(p-d3));
 41 }
 42
 43 points a[110];
 44 int n,i;
 45
 46 points l[110];
 47 int pl=0;
 48 points r[110];
 49 int pr=0;
 50
 51 double rr;
 52 double x11,y11,x22,y22;
 53 double k,b;
 54 double x_temp;
 55
 56 double C,S;
 57
 58 int main(){
 59 //    freopen("T2.in","r",stdin);
 60 //    freopen("T2.out","w",stdout);
 61
 62     scanf("%d%lf",&n,&rr);
 63
 64     for(i=1;i<=n;i++)scanf("%lf%lf",&a[i].x,&a[i].y);
 65
 66     sort(a+1,a+1+n,cmp);
 67
 68     x11=a[1].x;
 69     y11=a[1].y;
 70     x22=a[n].x;
 71     y22=a[n].y;
 72
 73     k=(y22-y11)/(x22-x11);
 74     b=y11-k*x11;
 75
 76     for(i=2;i<n;i++){
 77         x_temp=(a[i].y-b)/k;
 78
 79         if(a[i].x<x_temp){
 80             pl++;
 81             l[pl].x=a[i].x;
 82             l[pl].y=a[i].y;
 83         }
 84         else{
 85             pr++;
 86             r[pr].x=a[i].x;
 87             r[pr].y=a[i].y;
 88         }
 89     }
 90
 91     C=getd(a[1],l[1])+getd(a[1],r[1])+getd(a[n],l[pl])+getd(a[n],r[pr]);
 92
 93     for(i=1;i<pl;i++)C+=getd(l[i],l[i+1]);
 94     for(i=1;i<pr;i++)C+=getd(r[i],r[i+1]);
 95
 96     S=getv(a[1],a[n],l[pl])+getv(a[1],a[n],r[pr]);
 97
 98     for(i=1;i<pl;i++)S+=getv(a[1],l[i],l[i+1]);
 99     for(i=1;i<pr;i++)S+=getv(a[1],r[i],r[i+1]);
100
101     S+=C*rr;
102     S+=pi*rr*rr;
103
104     C+=2*pi*rr;
105
106     printf("%.2lf %.2lf\n",C,S);
107
108 //    fclose(stdin);
109 //    fclose(stdout);
110
111     return 0;
112 }

Takuji与信徒:

首先你要搞一种数据结构,推荐BIT,毕竟常数小。

其次是离散化,如果不会请自行百度,就是先将坐标排序,每次操作时二分查找一下,就得到了实际操作位置。

1操作和3操作没啥可说的,只讲讲2操作。

如果开始的时候把初始序列读入并直接离散化,那么就会愉快的错掉,因为二分出的位置是不对的,2操作指定的坐标在初始序列中不存在,结果会是离散化到了其他坐标上面去。

正确的搞法如下:

1.读入原始序列,将坐标和值存入数组,记为c[],然后不作任何操作;

2.读入指令,但不执行,而是先将指令存到数组当中,记为com[]。如果读到了2操作,那么在c[]中新存入一个元素,坐标为此次操作2指定的坐标,值为0,表示这个位置的值也有可能即将被修改,因为2操作的实质就是将一个原值为0的点进行修改;

3.对c[]进行离散化;

4.处理com[]中的指令,这时若遇到操作2,就可以采取与操作1同样的方式处理了。操作1、3不再赘述。

标程:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<ctime>
  6 #include<cstdlib>
  7
  8 #include<string>
  9 #include<stack>
 10 #include<queue>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<map>
 14
 15 using namespace std;
 16
 17 inline void read(int &x){
 18     x=0;
 19     char t=getchar();
 20     bool f=0;
 21
 22     while(t<‘0‘ || t>‘9‘){
 23         if(t==‘-‘)f=1;
 24         t=getchar();
 25     }
 26
 27     while(t>=‘0‘ && t<=‘9‘){
 28         x=(x<<3)+(x<<1)+t-‘0‘;
 29         t=getchar();
 30     }
 31
 32     if(f)x=-x;
 33 }
 34
 35 void add(int,int);
 36 int pre(int);
 37
 38 struct abc{
 39     int rank,data;
 40 } c[1000010],temp;
 41
 42 int tree[1000010];
 43
 44 bool cmp(abc x,abc y){
 45     return x.rank<y.rank;
 46 }
 47
 48 struct bcd{
 49     int f;
 50     int d1,d2;
 51 } com[500010];
 52
 53 int n,m,i,j;
 54 int p,l,r;
 55
 56 int main(){
 57 //    freopen("T3.in","r",stdin);
 58 //    freopen("T3_2.out","w",stdout);
 59
 60     memset(tree,0,sizeof(tree));
 61
 62     read(n);
 63
 64     for(i=1;i<=n;i++){
 65         read(c[i].rank);
 66         read(c[i].data);
 67     }
 68
 69     read(m);
 70
 71     for(i=1;i<=m;i++){
 72         read(com[i].f);
 73         read(com[i].d1);
 74         read(com[i].d2);
 75
 76         if(com[i].f==2){
 77             n++;
 78             c[n].rank=com[i].d1;
 79             c[n].data=0;
 80         }
 81     }
 82
 83     sort(c+1,c+1+n,cmp);
 84     n++;
 85     c[n].rank=2147483647;
 86
 87     for(i=1;i<=n;i++)add(i,c[i].data);
 88
 89     for(i=1;i<=m;i++){
 90         if(com[i].f==1 || com[i].f==2){
 91             temp.rank=com[i].d1;
 92             p=lower_bound(c+1,c+1+n,temp,cmp)-c;
 93             add(p,com[i].d2);
 94         }
 95         else{
 96             temp.rank=com[i].d1;
 97             l=lower_bound(c+1,c+1+n,temp,cmp)-c;
 98             temp.rank=com[i].d2;
 99             r=lower_bound(c+1,c+1+n,temp,cmp)-c;
100             if(c[r].rank>com[i].d2)r--;
101             printf("%d\n",pre(r)-pre(l-1));
102
103         }
104     }
105
106 //    fclose(stdin);
107 //    fclose(stdout);
108
109     return 0;
110 }
111
112 void add(int p,int x){
113     while(p<=n){
114         tree[p]+=x;
115         p+=p&-p;
116     }
117 }
118
119 int pre(int p){
120     int ans=0;
121     while(p>=1){
122         ans+=tree[p];
123         p-=p&-p;
124     }
125     return ans;
126 }
时间: 2024-12-09 20:05:10

互测六 题解 9.18 圆润的多边形&Takuji与信徒的相关文章

小组互测评论

时间:2014年5月9号 互测小组:本组与刘铸辉(组长)组 第一版本互测初步评论: 杨波:整体界面很好,要实现的基本功能实现了: 崔海营:日程录入模块实现的很好,调用了系统设计: 周亚豪:每周日历表这个模块导入效果不错,整体界面良好: 蔡容玉:日程录入模块实现了,但是好像录入了后在每天时间表的事件中没有及时更新: 闵芮:界面较简便,功能不错:期待后续版本: 张丹丹:软件界面不美观,手机屏幕利用率不高,但总体功能比较完善,对学生有一定的实用性. 高琪:界面清晰,功能明确,但是希望界面更好看:

首师大附中互测题:LJX的校园:入学典礼【C003】

[C003]LJX的校园:入学典礼[难度C]—————————————————————————————————————————————————————————————————————————————————————— [题目要求] LJX上中学啦!他与YSM,YSF,WHT,LTJ等人都是校友.今天,是他人生中“溺亡”的一天.今天,他要向同学们证明他的数学很“乐呵”. 于是,刚学会简单的A+B问题的他,在课上,向冤  家对头 斯沃琪 挑战 QAQ,斯沃琪 队有YZM,SJY,ZZQ等人.而LJX

[蒟蒻修炼计划][bzoj3670][2014湖北省队互测week2]似乎在梦中见过的样子

Description 已知一个字符串S,求它有多少个形如A+B+A的子串(len(A)>=k,len(B)>=1 ). Input 第一行一个字符串,第二行一个数 k. Output 仅一行一个数,表示满足条件的子串数. Sample Input aaaaa 1 Sample Output 6 HINT 对于 100%的数据:n<=15000 , k<=100,且字符集为所有小写字母. Solution 这道题时限15s,明显O(n^2)可以过.那么如果枚举某一端形成新的子串,用

【河北省队互测】 gcd BZOJ 2818

Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的 数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 Sample Output 4 HINT hint 对于样例(2,2),(2,4),(3,3),(4,2) 1<=N<=10^7 思路 最近看了很多关于gcd和mod的题目. 通过最近几道题目了解了很多=.= 首先有这么一个性质:如果a∈[1,n],b∈[1,m],那么gcd(a,b)|k的有(n/k

集训队互测2016Unknown(UOJ191)

题目链接 前面部分和lzz的题解是一样的. 首先将输入点(x,y)变为(-y,x)然后,只需找一个向量与(-y,x)的点积最大,即找一个向量在(-y,x)上的投影最长.此时所有的点都是在x轴上方的,容易发现答案一定是在凸包上的,再继续观察,如果有一个点在凸包而不在上凸包上,那么它的右上角及左上角一定有一个点,因此这个点一定不是最优的,所以答案一定在上凸包上,且可以在上凸包上二分. 对于subtask5,使用线段树,每个节点存储这个区间的凸包,合并凸包的话可以将两个凸包上的点归并后线性做凸包. 从

EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了正解但-1输成0了缅怀 而且这题不能用读优玄学 思路也很新奇,先跑一遍MST,判断是否有无解的情况 然后看一下MST中与1相连的边有几条 如果小于k那么我们把所有与1相连的边减上一个值使它们优先被选,然后跑MST 大于k就加上去即可 注意到这个值可以二分,因此不停做MST即可 CODE #inclu

tree (一本通练习||清华集训互测)

tree 内存限制:512 MiB 时间限制:3000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树.题目保证有解. 输入格式 第一行V,E,need分别表示点数,边数和需要的白色边数.接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色). 输出格式 一行表示所求生成树的边权和.V<=50000,E<=100000,所有数据边权为[1,10

jzoj 2867. 【集训队互测 2012】Contra

Description 偶然间,chnlich 发现了他小时候玩过的一个游戏"魂斗罗",于是决定怀旧.但是这是一个奇怪的魂斗罗 MOD. 有 N 个关卡,初始有 Q 条命. 每通过一个关卡,会得到 u 分和1条命,生命上限为 Q.其中 u=min(最近一次连续通过的关数,R). 若没有通过这个关卡,将会失去1条命,并进入下一个关卡. 当没有生命或没有未挑战过的关卡时,游戏结束,得到的分数为每关得到的分数的总和. 由于 chnlich 好久不玩这个游戏了,每条命通过每个关卡的概率均为p(

十连测Day1 题解

A. 奥义商店 有一个商店,n个物品,每个物品有一个价格和一种颜色. 有m个操作,操作有两种,一种是修改一个位置的价格,另一种是购买,每次购买指定一个公差d和一个位置k,找到包含这个位置k公差为d的同色最长等差数列,买下所有物品.让你给这个位置染成t种颜色中的一种(你来指定),其他位置会随机染成t种颜色之一,并保证这n-1个物品中第j种颜色的恰好有c[j]个.求最小期望花费保留四位小数. 注意询问相互独立,询问不会买走物品. 1<=n,m<=10^5,∑t<=2*10^5. 首先我们考虑