码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ Monthly,Feburary 2012 部分题解

时间:2015-02-07 20:26:47      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:点击打开链接

ZOJ 3573 Under Attack

距离做这套题到写题解间隔比较久,题意有些忘了。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;

typedef long long ll;
const int N = 15005;
int sum[N], a[N];

template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}

int main() {
	int n;
	while(~scanf("%d", &n)) {
		memset(a, 0, sizeof a);
		memset(sum, 0, sizeof sum);
		int l, r, d;
		while(true) {
			rd(l); rd(r); rd(d);
			if(l == -1) break;
			
			a[l] += d;
			a[r+1] -= d;
		}
		int L = 0, R = 0;
		sum[0] = a[0];
		for(int i = 1; i <= n; i ++) {
			sum[i] = sum[i-1] + a[i];
		//	printf("%d ", sum[i]);
			if(sum[i] > sum[L]) L = i;
			if(sum[i] >= sum[R]) R = i;
		}
		
		printf("%d %d\n", L, R);
	}

	return 0;
}



题目链接:点击打开链接

ZOJ 3574 Under Attack II

题意:

第一行输入a,b

第二行输入k对数字表示k条直线的点斜式

给定二维平面的一个区域 [a,b],用k条直线分割此平面,问分割成多少块(一个点至多被2条直线经过)

思路:

对于一条直线我们能求出这条直线与 x=a , x=b 的两个交点。

当我们插入一条直线时能增加的平面个数就是这条直线下方 x=a 与先前的直线交点个数- x=b与先前的直线交点个数的差的绝对值。

维护两个树状数组来记录x=a和x=b的交点个数

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;
const int inf = 1e9;
const int mod = 1e9+7;
const int MAXN = 30010;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
typedef long long ll;
struct Tree{
	int c[30000*3+10], maxn;
	void init(int x){ maxn = x+10; memset(c, 0, sizeof c); }
	inline int Lowbit(int x){ return x&(-x); }
	void change(int i, int x)//i点增量为x  
	{
		while (i <= maxn)
		{
			c[i] += x;
			i += Lowbit(i);
		}
	}
	int sum(int x){//区间求和 [1,x]  
		int ans = 0;
		for (int i = x; i >= 1; i -= Lowbit(i))
			ans += c[i];
		return ans;
	}
}t[2];
struct node{
	int k, b, y1, y2;
	node(){}
	node(int a, int y):k(a), b(y){}
}a[MAXN];
int l, r, n;
vector<int>G;
int main() {
	while (~scanf("%d %d", &l, &r)) {
		G.clear();
		rd(n);
		for (int i = 1, k, b; i <= n; i++){
			rd(k); rd(b);
			a[i] = node(k, b);
			a[i].y1 = k*l + b; a[i].y2 = k*r + b;
			G.push_back(a[i].y1); G.push_back(a[i].y2);
		}
		G.push_back(G[0] - 1);
		sort(G.begin(), G.end()); G.erase(unique(G.begin(), G.end()), G.end());
		for (int i = 1; i <= n; i++){
			a[i].y1 = lower_bound(G.begin(), G.end(), a[i].y1) - G.begin() + 1;
			a[i].y2 = lower_bound(G.begin(), G.end(), a[i].y2) - G.begin() + 1;
		}
		t[0].init(G.size()); t[1].init(G.size());
		int ans = 1;
		for (int i = 1; i <= n; i++){
			int x = t[0].sum(a[i].y1 - 1), y = t[1].sum(a[i].y2 - 1);
			ans += abs(x - y) + 1;
			t[0].change(a[i].y1, 1);
			t[1].change(a[i].y2, 1);
		}
		pt(ans); putchar('\n');
	}
	return 0;
}

题目链接:点击打开链接

ZOJ 3575 Under Attack 

给定一个椭圆,问最多能覆盖平面上多少个点。

思路:枚举任意两个点就能确定一个椭圆的2个圆心。然后判断这个圆心的覆盖点数,取最大值即可。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAX_N = 207;
const double eps = 1e-7;

struct Point {
	double x, y;
	Point () {
		
	}
	Point (double _x, double _y) {
		x = _x, y = _y;
	}	
	Point operator + (Point rhs) {
		return Point(x + rhs.x, y + rhs.y);
	}
	Point operator - (Point rhs) {
		return Point(x - rhs.x, y - rhs.y);
	}
	Point operator * (double t) {
		return Point(x * t, y * t);
	}
	double len() {
		return sqrt(x * x + y * y);
	}
	Point turn(double rad) {
		return Point(x * rad / len(), y * rad / len());
	}
};

double a, b;
int n;
Point p[MAX_N];

double dis(int i, int j) {
//	printf("%f %f\n", (p[i] - p[j]).x, (p[i] - p[j]).y);
	return (p[i] - p[j]).len();
}

int get(Point o) {
	int cnt = 0;
	for (int i = 0; i < n; ++i) {
		double l = (p[i] - o).len();
	//	printf("qqqqqqq %f %f %f\n", o.x, o.y, l);
		if (l - a < eps) ++cnt;
	}
	return cnt;
}

int main() {
	while (2 == scanf("%lf%lf", &a, &b)) {
		scanf("%d", &n);
		for (int i = 0; i < n; ++i) {
			scanf("%lf%lf", &p[i].x, &p[i].y);
			p[i].y *= a / b;
		}
		if(n == 0 || fabs(a) < eps || fabs(b) < eps) {
			printf("0\n");
			continue;
		}
		int ans = 1;
		for (int i = 0; i < n; ++i) {
		//	printf("%lf %lf", p[i].x, p[i].y);
			for (int j = i + 1; j < n; ++j) {
				double d = dis(i, j);
				if (2 * a - d < -eps) continue;
				Point o = (p[i] + p[j]) * 0.5;
				double l = sqrt(a * a - d * d / 4);
				Point F = Point(-(p[i] - p[j]).y, (p[i] - p[j]).x);
			//	printf("zzzzzzzzzz %f %f %f %f\n", F.x, F.y, o.x, o.y);
				Point up = o + F.turn(l);
				Point down = o - F.turn(l);
				ans = max(ans, get(up));
				ans = max(ans, get(down));
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}


题目链接:点击打开链接

zoj 3576 Count the Length

题意:

给定n*m的方格,左下角为红色,红蓝相间绘制的矩阵,问副对角线的长度。

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;
const int inf = 1e9;
const int mod = 10007;
const int MAXN = 305;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
typedef long long ll;
ll n, m;
ll gcd(ll a, ll b) {
	while(a > 0 && b > 0) {
		if(a > b) a %= b;
		else b %= a;
	}
	return a+b;
}
int main() {
	while(~scanf("%lld%lld", &n, &m)) {
		double ans = sqrt((double)n*n+m*m);
		if(n%2==0&&m%2==0) {
			ans /= 2.0;
		} else {
			int g = gcd(n, m);
			n /= g; m/= g;
			double d = (double)(n*m+1) / (double)(n*m*2);
			ans *= d;
		}
		printf("%.3f\n", ans);
	}
	return 0;
}
题目链接:点击打开链接

zoj 3578 Matrix

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAX_N = 1007;

struct Node {
    int x, y, ax, ay, h;
    Node () {

    }
    Node (int _x, int _y, int _ax, int _ay, int _h) {
        x = _x, y = _y;
        ax = _ax, ay = _ay;
        h = _h;
    }
};

int N, M, C;
Node mat[MAX_N];

bool cross2(int i,int j){
    if(mat[i].x >= mat[j].ax||mat[j].x >= mat[i].ax) return false;
    if(mat[i].y >= mat[j].ay||mat[j].y >= mat[i].ay) return false;
    return true;
}

bool cross(int i, int j) {
    int a[4][2];

    a[0][0] = mat[i].x, a[0][1] = mat[i].y;
    a[1][0] = mat[i].x, a[1][1] = mat[i].ay;
    a[2][0] = mat[i].ax, a[2][1] = mat[i].y;
    a[3][0] = mat[i].ax, a[3][1] = mat[i].ay;
    for (int ii = 0; ii < 4; ++ii) {
        if (mat[j].x <= a[ii][0] && a[ii][0] <= mat[j].ax &&
            mat[j].y <= a[ii][1] && a[ii][1] <= mat[j].ay) return true;
    }
    return false;
}

int main() {
    while (3 == scanf("%d%d%d", &N, &M, &C)) {
        memset(mat, 0, sizeof mat);
        for (int i = 1; i <= C; ++i) {
            int x, y, a, b, h;
            scanf("%d%d%d%d%d", &a, &b, &h, &x, &y);
            mat[i] = Node (x, y, x + a, y + b, 0);
            int now = 0;
            for (int j = 1; j < i; ++j) {
                if (cross2(i, j)) {
                    now = max(now, mat[j].h);
                }
            }
            mat[i].h = now + h;
        }
        int ans = 0;
        for (int i = 1; i <= C; ++i) {
            //printf("%d %d %d %d %d\n", mat[i].x, mat[i].y, mat[i].ax, mat[i].ay, mat[i].h);
            ans = max(ans, mat[i].h);
        }
        printf("%d\n", ans);
    }
    return 0;
}

I的话大概就是状压dp,然后上物理公式啥的,求角度时可以二分一下求比较简单







ZOJ Monthly,Feburary 2012 部分题解

标签:

原文地址:http://blog.csdn.net/qq574857122/article/details/43605261

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!