ZOJ Monthly,Feburary 2012 部分题解

题目链接:点击打开链接

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,然后上物理公式啥的,求角度时可以二分一下求比较简单

时间: 2025-01-14 05:18:45

ZOJ Monthly,Feburary 2012 部分题解的相关文章

ZOJ Monthly, August 2012 题解

A: 题目链接:点击打开链接 Alice's present #include <cstdio> #include <iostream> #include <cstring> #include <string> #include <map> #include <queue> #include <set> #include <algorithm> using namespace std; int n, m; in

ZOJ Monthly, November 2012

A.ZOJ 3666 Alice and Bob 组合博弈,SG函数应用 #include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 10000 + 100; int SG[maxn]; vector<int> g[maxn]; int mex(int u) { //minimal exc

ZOJ Monthly, July 2012

zoj 3622.Magic Number   水题 先找规律生成区间[1,1<<32-1]内的所有Magic Number,计算出来只有40多个,然后就随便YY了. void init() { int a[5] = { 1,2,5,25,125 }; ll Max = (1ll<<32)-1; for(ll tmp =1; tmp<=Max; tmp *=10) { for(int i=0; i<5; ++i){ ll t = tmp * a[i]; if(t>

ZOJ Monthly, February 2012 C,D,F,H

C:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3573 瞎搞题,可以用线段树+lazy过.CB曾经出过一个类似的,可以0(N)的处理.左边加右边减,边走边算. #include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #incl

ZOJ Monthly, September 2003【部分题解】

今天比赛做了一下这套题目.出了四道.两道水题,两道DP 比赛链接:http://vjudge.net/contest/view.action?cid=51404#problem/B 上来搞了一道水题之后就搞B题 题意很好理解,上来看了一下就懂了.以为是规律有循环节,没看wa那么多毅然决然提交,wa了一发. A = "^__^" and B = "T.T",C = BA = "T.T^__^".然后A=B,B=C,一直重复这个操作,问最后第n位的字

135 - ZOJ Monthly, August 2014

135 - ZOJ Monthly, August 2014 A:构造问题,推断序列奇偶性.非常easy发现最小值不是1就是0.最大值不是n就是n - 1,注意细节去构造就可以 E:dp.dp[i][j]表示长度i,末尾状态为j的最大值,然后每一个位置数字取与不取,不断状态转移就可以 G:就一个模拟题没什么好说的 H:dfs,每次dfs下去,把子树宽度保存下来,然后找最大值,假设有多个.就是最大值+cnt宽度 I:构造,假设r * 2 > R,肯定无法构造.剩下的就二分底边.按等腰三角形去构造就

JOI 2012 fish 题解

题目大意: 给你一个0/1/2序列Ai,每个值Ai有一个权值Pi.如果两个值的权值Pi和Pj满足Pi≥2Pj,那么Ai就会把Aj吔掉,也就是说Ai, Aj不能共存. 称Ai的一个子序列的特征三元组为(Sum0, Sum1, Sum2),其中Sump为子序列中的Ai=p的个数.当然这里要求所有值可以共存. 求:Ai的所有合法子序列的特征三元组的种类数目.1≤N≤200000. 这道题可谓是难题(对于我),同样是听完题解外加问人外加参考代码才回的,我们给个原题网址(日文版)戳一下http://www

ZOJ Monthly, June 2014——Grouping

题目连接 题意: n个点,m条边 每条边两个整数a.b,表示a到b的有向边 求,至少需要几个集合,使得:每个集合中的元素互相不能到达 N(1≤ N≤ 100000), M(1≤ M≤ 300000) 分析: 相连的两个点不能在同一个集合中,那么,对于一个长度为n的链,至少需要n个集合:如果链中有环,相当于把环展开,这个就需要缩点处理 就是缩点之后求点权最长路 注意:模板中scc_cnt是从1开始的,如果使用缩点后的图,初始化时需要初始化总点数加一 因为总点数有限,用拓扑排序每次删除所有入度为零的

记次浙大月赛 134 - ZOJ Monthly, June 2014

链接 虽做出的很少,也记录下来,留着以后来补..浙大题目质量还是很高的 B 并查集的一些操作,同类和不同类我是根据到根节点距离的奇偶判断的,删点是直接新加一个点,记得福大月赛也做过类似的,并差集的这类关系题目还是比较常见的,有空深究一下. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6