题目链接:点击打开链接
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,然后上物理公式啥的,求角度时可以二分一下求比较简单