- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
A. Easy Problem
这题是special judge,即答案不唯一的题。题意是输入一个大于4的正整数N,然后让你输出3个比N小的数。一种解法是不管N,全部输出1 2 3。
举办方出这题是为了提醒我们明日的正赛会有这样的special judge题。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
B. Number lengths (FOJ1050)
题意:输入N,输出N的阶乘是几位数。
思路:用以10为底的对数运算,能计算一个数是几位数(好好思考为什么)。而对数内部的乘法,可以拆开变成加法运算。(以下代码用GNU C++提交)
#include <cstdio>
#include <cmath>
using namespace std;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
double ans = 1;
for (int i = 2; i <= n; i++) ans += log10(i);
printf("%d\n", int(ans));
}
return 0;
}
这样的代码已经能AC了,不过用时78ms。看到有人0ms AC,说明还是能再优化的。见斯特林公式。公式两边同取对数,注意代码中对公式的稍许变化,避免了sqrt运算和提高运算精度。
#include <cstdio>
#include <cmath>
using namespace std;
const double PI = atan(1.0)*4;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
int ans = (int)((n*log(n)-n+0.5*log(2*n*PI))/log(10.0))+1;
printf("%d\n", ans);
}
return 0;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C. 土地划分( FOJ1015)
题意:在一个矩形土地里用L条线段划分,问能划分出多少块土地。
思路:首先要推导出土地数只跟矩形内的交点个数有关。想想看,L条线段如果互不相交(端点相交不算,以下均如此计算),则可以划分出L+1块土地。又线段间每产生一个交点,就多划分出一份土地。所以土地总数就是L+1+交点数。
故接下来的难点是如何通过两个线段的端点(点a1,点a2,点b1,点b2),来判断线段a与b是否相交。这里可以用快速排斥和跨立实验。更简单的,不用管那么多原理,计算几何题本来就需要经常套用模板求解,在大白书(刘汝佳的《算法竞赛入门经典——训练指南》第4章),有很多优秀的模板,包括判断两线段是否“规范相交”的SegmentProperIntersection函数。下面的代码从第4至第19行是相应的计算几何模板(实际刷题都是整套模板贴的,模板很长,这里为了简洁,只留下必须的内容),故主函数非常简单,只要每得到一个新的线段,就跟之前的所有线段比较,累加相交次数即可。
#include <iostream>
#include <cmath>
using namespace std;
const double eps = 1e-10;
int dcmp(double x) {if(fabs(x)<eps) return 0; else return x<0?-1:1;}
struct Point{
double x, y;
Point(double a=0, double b=0):x(a),y(b) { }
};
typedef Point Vector;
Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }
double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x; }
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2) {
double c1 = Cross(a2-a1,b1-a1), c2 = Cross(a2-a1,b2-a1),
c3 = Cross(b2-b1,a1-b1), c4 = Cross(b2-b1,a2-b1);
return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
int main() {
Point P[60];
int w, h, L, i, j, ans;
while (cin >> w >> h, w&&h) {
cin >> L >> P[0].x >> P[0].y;
ans = L+1;
for (i = 1; i <= L; i++) {
cin >> P[i].x >> P[i].y;
for (j = 1; j < i; j++) {
ans += SegmentProperIntersection(P[j-1],P[j],P[i-1],P[i]);
}
}
cout << ans << endl;
}
return 0;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
D. Key problem(FOJ1692)
这题我之前的一篇博客整理的很好很详细了:FOJ 1692 Key problem