CTU Open Contest 2019

我主看C和F
C题就是一个套板子题

题意
求圆与矩形的相交面积
把圆和凸包相交面积板子套上即可

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<numeric>
#include<deque>
using namespace std;
typedef long long ll;
#define inf 1000000000000
#define M 100009
#define eps 1e-12
#define PI acos(-1.0)
struct Point
{
	double x, y;
	Point() {}
	Point(double xx, double yy) {x = xx; y = yy;}
	Point operator -(Point s) {return Point(x - s.x, y - s.y);}
	Point operator +(Point s) {return Point(x + s.x, y + s.y);}
	double operator *(Point s) {return x * s.x + y * s.y;}
	double operator ^(Point s) {return x * s.y - y * s.x;}
} p[M];
double max(double a, double b) {return a > b ? a : b;}
double min(double a, double b) {return a < b ? a : b;}
double len(Point a) {return sqrt(a * a);}
double dis(Point a, Point b) {return len(b - a);} //两点之间的距离
double cross(Point a, Point b, Point c) //叉乘
{
	return (b - a) ^ (c - a);
}
double dot(Point a, Point b, Point c) //点乘
{
	return (b - a) * (c - a);
}
int judge(Point a, Point b, Point c) //判断c是否在ab线段上(前提是c在直线ab上)
{
	if (c.x >= min(a.x, b.x)
	        && c.x <= max(a.x, b.x)
	        && c.y >= min(a.y, b.y)
	        && c.y <= max(a.y, b.y)) return 1;
	return 0;
}
double area(Point b, Point c, double r)
{
	Point a(0.0, 0.0);
	if (dis(b, c) < eps) return 0.0;
	double h = fabs(cross(a, b, c)) / dis(b, c);
	if (dis(a, b) > r - eps && dis(a, c) > r - eps) //两个端点都在圆的外面则分为两种情况
	{
		double angle = acos(dot(a, b, c) / dis(a, b) / dis(a, c));
		if (h > r - eps) return 0.5 * r * r * angle; else if (dot(b, a, c) > 0 && dot(c, a, b) > 0)
		{
			double angle1 = 2 * acos(h / r);
			return 0.5 * r * r * fabs(angle - angle1) + 0.5 * r * r * sin(angle1);
		} else return 0.5 * r * r * angle;
	} else if (dis(a, b) < r + eps && dis(a, c) < r + eps) return 0.5 * fabs(cross(a, b, c)); //两个端点都在圆内的情况
	else//一个端点在圆上一个端点在圆内的情况
	{
		if (dis(a, b) > dis(a, c)) swap(b, c); //默认b在圆内
		if (fabs(dis(a, b)) < eps) return 0.0; //ab距离为0直接返回0
		if (dot(b, a, c) < eps)
		{
			double angle1 = acos(h / dis(a, b));
			double angle2 = acos(h / r) - angle1;
			double angle3 = acos(h / dis(a, c)) - acos(h / r);
			return 0.5 * dis(a, b) * r * sin(angle2) + 0.5 * r * r * angle3;
		} else
		{
			double angle1 = acos(h / dis(a, b));
			double angle2 = acos(h / r);
			double angle3 = acos(h / dis(a, c)) - angle2;
			return 0.5 * r * dis(a, b) * sin(angle1 + angle2) + 0.5 * r * r * angle3;
		}
	}
}//圆与凸多边形相交面积
int main()
{
	double x, y, r;
	scanf("%lf%lf%lf%lf%lf%lf%lf",&x,&y,&r,&p[1].x,&p[1].y,&p[3].x,&p[3].y);
	p[2].y = p[1].y;
	p[2].x = p[3].x;
	p[4].y = p[3].y;
	p[4].x = p[1].x;
	p[5] = p[1];
	Point o(x, y);
	for (int i = 1; i <= 5; i++)
	{
		p[i] = p[i] - o;
	}
	double ans = 0;
	for (int i = 1; i <= 4; i++)
	{
		double ss = area(p[i], p[i + 1], r);
		if (cross(Point(0, 0), p[i], p[i + 1]) > 0)
			ans += ss;
		else
			ans -= ss;
	}
	printf("%.4f\n",fabs(ans));
	return 0;
}

F题类似与三分,但三分是严格单调的,前期用三分一直wa,才发现这个问题,于是设置一个三分次数的限制即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<numeric>
#include<deque>
#include<queue>
#include<sstream>
using namespace std;
typedef long long ll;
const ll linf = 0x3f3f3f3f3f3f3f3f;
ll n, k;
ll x[1000005];
ll f(ll d)
{
	ll ans = 0;
	ll D = d;
	for (int i = 0; i < n; i++)
	{
		ans += abs(D - x[i]);
		D += k;
	}
	return ans;
}
int main()
{
	scanf("%lld%lld", &n, &k);
	for (int i = 0; i < n; i++)
		scanf("%lld", &x[i]);
	sort(x, x + n);
	ll l = -1e12, r = 1e12;
	ll ans = linf;
	int po=100;
	while(po--)
	{
		ll mid = l + (r - l) / 3;
        ll mmid = r - (r - l) / 3;
        ll t1=f(mid);
        ll t2=f(mmid);
        if(t1 > t2)
        {
            l = mid;
        }
        else
        {
            r = mmid;
        }
        ans = std::min(ans, std::min(t1, t2));
	}
	printf("%lld\n", ans);
	return 0;
}
/*
3 1
2 5 7


10 4
140 26 69 55 39 64 2 89 78 421
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值