Problem A. 切蛋糕
File: cut.*
Time limit: 1s
Memory limit: 256MB
A 和B 想要切蛋糕来吃,蛋糕可以看作一个m*n 的矩形,由分割线划分。蛋糕由A 来切,他切蛋糕的
方式分为两步:
1. 沿着蛋糕的某条分割线将蛋糕分成两半。
2. 如果两块蛋糕大小一样,A 吃掉其中的一块蛋糕,把另一块给B 吃,结束切蛋糕。否则从较大块蛋糕
中切去较小块蛋糕那么大的部分并吃掉切下的部分,重复第二步。
另外A 不希望连续两次都从同一块蛋糕中切。
求A 最多能吃多少单位蛋糕,每单位蛋糕就是一个1*1 的单位矩形。
Input
第一行包含两个整数m 和n,(1<=m; n<=1e9)。
Output
输出一个数c,表示A 最多能吃到的蛋糕数量。
Examples
Input
6 5
Output
24
Subtasks
对于40% 的数据,m; n<=1000。
对于100% 的数据,m; n<=1e9。
注:只能按一开始的方案切(即一开始横着切只能一直横着切)
假设横着切,则答案即此时可以吃的横的长度*竖直的长
设一开始横着切下了p,剩下了q
如果只切一次,则应满足p=q;
如果切两次,则应满足q-p=p;
如果切三次,应满足p-(q-p)=q-p
如果切四次,应满足q-p-[p-(q-p)]=p-(q-p)
......
依次类推下去,经过整理,我们可以得到以下式子
p=q;
2p=q;
3p=2q;
5p=3q;
8p=5q;
......
于是我们惊讶地[也许并不]发现:p、q的系数竟然各是一个斐波那契数列。
同理,当竖着切时也是一样的,我们只需要横着竖着各切一次取max
于是就可以愉快地写代码啦
#include
#include
#include
#include
#include
#include
using namespace std; long long n, m; long long fib[100]; long long calc(long long a, long long b) { if (a == b) return a; if (a < b) swap(a, b); return calc(b, a - b); } long long check(long long x, long long y) { fib[0] = 1; fib[1] = 1; for(int i = 2; i < 75; i++) fib[i] = fib[i - 1] + fib[i - 2]; long long res = 0; for(int i = 1; i < 70; i++) { if (x * fib[i] % fib[i + 1] == 0) { long long z = x * fib[i] / fib[i + 1]; res = max(res, (x - calc(x, z)) * y); } } return res; } int main() { // freopen("cut.in", "r", stdin); // freopen("cut.out", "w", stdout); scanf("%lld%lld", &n, &m); printf("%lld\n", max(check(n, m), check(m, n))); }
Problem B. 黑与白
File: bw.*
Time limit: 1s
Memory limit: 256MB
考虑一个无限的黑白棋盘,在棋盘上有个直角坐标系来规定每个顶点的坐标。现在有人在棋盘上画了条
不相交的闭合曲线,求在这条曲线内部的黑色格子与白色格子数量。保证曲线的顶点都在棋盘格子的顶
点处,且曲线上的边都平行于坐标轴。
Input
第⼀⾏包含整数n(1<=n<=50000) 表示曲线上的顶点数量。
接下来的n 行,每行包含两个整数,表示顶点的坐标。顶点以逆时针的顺序给出。坐标大小的绝对值不
超过1e9。
Output
输出两个数b 和w,表⽰曲线内部的黑色格子和白色格子数量。
Examples
Input
12
1 0
2 0
2 1
3 1
3 2
2 2
2 3
1 3
1 2
0 2
0 1
1 1
Output
1 4
Subtasks
对于10% 的数据,n<=4。
对于30% 的数据,n<=6。
对于60% 的数据,n<=100。
对于100% 的数据,n<=50000。
注:只能走直线,且左下角第一个格子[也就是(0,0)、(1,0)、(0,1)、(1,1)所围成的小方格]为黑色
大概就是这个样子QUQ
解析:
一开始引入了一个叫做扫描线的东西,就是一条线一下扫过去记录经过的线段,然后求面积。
具体做法:(原谅我拙劣的画图技巧)
黑色框->要求的图形,蓝线->扫描线,x、y按从小到大排列
当扫描线扫到x1位置时将y1,y3压入队列,再扫到x2时将y2压入队列(注意要从小到大排序!!)
则x1-x2间面积为(y3-y1)*(x2-x1),同理,x2-x3间面积为(y3-y2)*(x3-x2).....
but据说很不好写,蒟蒻的我也不会代码,如果有哪位聚聚会的话请务必告诉我。
因此我们需要换个思路。
由于只能走直线,因此我们可以发现向右走的线段的长度一定等于向左走的线段长度(逆时针走)
因此我们可以看出所求的图形面积即图三中蓝色的部分减去橙色的部分
因此只要用向左走的面积减去向右走的面积
但这样求比较困难,因此我们可以用图四中的方法来求
即绿色部分减去粉色部分(每一个矩形都可以这样来求)
又因为我们知道左下角第一个小方格为黑色的,因此我们可以在求矩形面积是顺便把黑白方格数求出来
然后上代码。
#include
#include
#include
#include
using namespace std;
int n;
long long X[120000], Y[120000], ansx, ansy;
void solve(long long x, long long y, int c) {
long long p = (x >> 1) * (y >> 1) + ((x + 1) >> 1) * ((y + 1) >> 1);
long long q = x * y - p;
ansx += p * c;
ansy += q * c;
}
int main(){
freopen("bw.in", "r", stdin);
freopen("bw.out", "w", stdout);
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%lld%lld", &X[i], &Y[i]);
X[n + 1] = X[1];Y[n + 1] = Y[1];
for(int i = 1; i <= n; i++) {
if (Y[i] == Y[i + 1]) {
solve(X[i], Y[i], 1);//往左加
solve(X[i + 1], Y[i + 1], -1);//往右减
}
}
printf("%lld %lld\n",ansx, ansy);
}
Problem C. cookie
File: cookie.*
Time limit: 1s
Memory limit: 256MB
由于不想吃饭了,你打算吃曲奇度日。曲奇散乱地排布在桌子上,而你用上帝视角看着它们,每一个曲奇
都看得清清楚楚。你突然想到一个问题,如果你处在这些曲奇中间,能不能清楚地看到每个曲奇呢?你
抽象了一下这个问题:有限平面上有n 个不相交的圆,询问是否存在一个点,从这个点能看到所有的圆,
并且不存在一个圆的部分被另一个圆挡住。
Input
第一行包含三个整数n; x; y(1<=n<=10; 4<=x; y<=1e4),零食个数为n,桌子的四个角为
(0; 0); (x; 0); (0; y); (x; y)。
接下来的n 行,每行三个整数表示零食的横坐标、纵坐标和半径。
Output
如果不存在合法点,输出”No Point”,否则输出该点坐标,答案被认为正确,当且仅当与标准答案的相对
误差或绝对误差不超过-1e5。
Input
4 10 10
2 2 2
8 8 2
2 8 2
8 2 2
Output
5.0 5.0
注:*只输出一组解就行
*点不一定在桌子上
解析:
n=1时,随便输出一个不在圆上的点
n=2时,找圆的公切线,然后找交点,再分别看切线将平面分成的部分中有哪些是可以看到两个圆的
n>=3时,同理
虽然话是这么说,但是我依然不会写啊【拍飞】
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cassert>
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define drep(i,a,b) for (int i=a;i>=b;i--)
#define INF int(1e8)
#define LL long long
#define pb push_back
#define mp make_pair
#define clr(a) memset(a,0,sizeof(a));
using namespace std;
const double eps=1e-10;
const int N=1000;
int n;
double limitx,limity;
struct point
{
double x,y;
point() {}
point(double _x,double _y) : x(_x),y(_y) {}
void print(){printf("%.6lf %.6lf\n",x,y);}
};
vector<point> can;
int operator ==(point a,point b)
{
return fabs(a.x-b.x)<=eps && fabs(a.y-b.y)<=eps;
}
struct Line
{
double a,b,c;
Line() {}
Line(point p,point q)
{
a=b=c=0;
if (p==q) assert(0);
if (fabs(p.y-q.y)<=eps)
{
a=0;b=1;c=-p.y;
return;
}
if (fabs(p.x-q.x)<=eps)
{
a=1;b=0;c=-p.x;
return;
}
a=1;
b=(q.x-p.x)/(p.y-q.y);
c=-p.x-b*p.y;
}
void print(){printf("%.4lf %.4lf %.4lf\n",a,b,c);}
};
point operator *(Line a,Line b)
{
if (fabs(a.a*b.b-a.b*b.a)<=eps) return point(limitx-2.*eps,limity-2.*eps);
return point( ( a.b*b.c-a.c*b.b)/(a.a*b.b-a.b*b.a) , ( a.a*b.c-a.c*b.a)/(a.b*b.a-a.a*b.b));
}
struct Circle
{
double x,y,r;
point o;
Circle() {}
Circle(double _x,double _y,double _r) : x(_x),y(_y),r(_r) {o=point(x,y);}
void read(){scanf("%lf%lf%lf",&x,&y,&r);o=point(x,y);}
void print(){printf("%.5lf %.5lf %.5lf\n",x,y,r);}
};
Circle cir[N];
point Rot(point a,point center,double ang)
{
return point((a.x-center.x)*cos(ang)-(a.y-center.y)*sin(ang)+center.x,(a.x-center.x)*sin(ang)+(a.y-center.y)*cos(ang)+center.y);
}
Circle Rot(Circle a,point center,double ang)
{
a.o=Rot(a.o,center,ang);
a.x=a.o.x;a.y=a.o.y;
return a;
}
double Dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Angle(point a,point b)
{
return atan2(b.y-a.y,b.x-a.x);
}
pair<Line,Line> Tangent(Circle x,Circle y)
{
double ang=Angle(x.o,y.o);
y=Rot(y,x.o, -ang );
double dis=Dis(x.o,y.o);
point mid=point(x.o.x+dis/(x.r+y.r)*x.r,x.o.y);
dis=dis/(x.r+y.r)*x.r;
double dltx=x.r*x.r/dis,dlty=sqrt(x.r*x.r-dltx*dltx);
point Up=point(x.o.x+dltx,x.o.y+dlty),Down=point(x.o.x+dltx,x.o.y-dlty);
if (Up==mid)
{
Up.y+=1.;
Down.y-=1.;
}
Up=Rot(Up,x.o,ang); Down=Rot(Down,x.o,ang); mid=Rot(mid,x.o,ang);
can.pb(mid);
return mp( Line(Up,mid), Line(Down,mid) );
}
pair<double,double> Tangent(Circle x,point y)
{
double ang=Angle(x.o,y);
y=Rot(y,x.o,-ang );
double dis=Dis(x.o,y);
point mid=y;
double dltx=x.r*x.r/dis,dlty=sqrt(x.r*x.r-dltx*dltx);
point Up=point(x.o.x+dltx,x.o.y+dlty),Down=point(x.o.x+dltx,x.o.y-dlty);
if (Up==mid)
{
Up.y+=1.;
Down.y-=1.;
}
Up=Rot(Up,x.o,ang); Down=Rot(Down,x.o,ang); mid=Rot(mid,x.o,ang);
return mp( Angle(mid,Up), Angle(mid,Down) );
}
int In2(double x,double l,double r)
{
if (x-M_PI*2.>l+1e-6 && x-M_PI*2.<r-1e-6) return 1;
if (x>=l+eps && x<=r-eps) return 1;
if (x+M_PI*2.>l+1e-6 && x+M_PI*2.<r-1e-6) return 1;
return 0;
}
int In(double x,double l,double r)
{
if (x>=l+eps && x<=r-eps) return 1;
return 0;
}
int In(point x,Circle c)
{
if (Dis(x,c.o)<=c.r-eps*3.) return 1;
return 0;
}
pair<double,double> seg[N];
int check(point x)
{
if (!(In(x.x,0,limitx) && In(x.y,0,limity))) return 0;
rep(i,1,n) if (In(x,cir[i])) return 0;
rep(i,1,n) seg[i]=Tangent(cir[i],x);
rep(i,1,n) if (seg[i].first>seg[i].second) seg[i].first-=2.*M_PI;
rep(i,1,n)
rep(j,1,n)
{
if (i==j) continue;
if (In2(seg[i].first,seg[j].first,seg[j].second) || In2(seg[i].second,seg[j].first,seg[j].second))
{
return 0;
}
}
return 1;
}
vector<Line> line;
point res;
int cnt;
int main()
{
freopen("cookie.in", "r", stdin);
freopen("cookie.out", "w", stdout);
scanf("%d%lf%lf",&n,&limitx,&limity);
rep(i,1,n) cir[i].read();
pair<Line,Line> x=Tangent(cir[1],cir[2]);
rep(i,1,n) rep(j,i+1,n)
{
pair<Line,Line> c=Tangent(cir[i],cir[j]);
line.pb(c.first);line.pb(c.second);
}
for(int i=0;i<line.size();i++)
for (int j=0;j<line.size();j++)
if (i!=j) can.pb(line[i]*line[j]);
can.pb(point(eps*2,eps*2));
can.pb(point(eps*2,limity-eps*2));
can.pb(point(limitx-eps*2,eps*2));
can.pb(point(limitx-eps*2,limity-eps*2));
for(int i=0;i<can.size();i++)
if (check(can[i])) cnt++,res=can[i];
if (!cnt) puts("No Point");
else printf("%.15lf %.15lf\n",res.x,res.y);
}