小Hi与法阵
题解
按照条件求解出最大的三角形和最小的三角形,然后求重心即可。
这里求解面积有两种方法:
- 海伦公式: p(p−a)(p−b)(p−c)−−−−−−−−−−−−−−−−−√ ,将三角形的每一条边求解出来,然后进行处理
- 用有向向量进行计算,如果设
a(x0,y0)
,
b(x1,y1)
,
c(x2,y2)
三点为三角形三个顶点,
A
为有向面积,那么
2A=∣∣∣∣∣x0x1x2y0y1y2111∣∣∣∣∣=x0y1+x2y0+x1y2−x2y1−x0y2−x1y0
然后需要注意就是针对浮点数判断要进行误差处理 eps=10−8 就可以了。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <cmath>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int MAXN = 50 + 5;
const int MAXM = 5e6 + 5;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
int N, U;
struct Point {
double x, y;
} P[MAXN];
int A[2][3];
double area(double x0, double y0, double x1, double y1, double x2, double y2) {
return fabs(x0 * y1 + x1 * y2 + x2 * y0 - x2 * y1 - y2 * x0 - y0 * x1) / 2.;
}
pair<double, double> getZx(int i, int j, int k) {
return make_pair((P[i].x + P[j].x + P[k].x) / 3., (P[i].y + P[j].y + P[k].y) / 3.);
}
int main() {
int _;
scanf("%d", &_);
while(_ --) {
scanf("%d%d", &N, &U);
for(int i = 0; i < N; i ++) {
scanf("%lf%lf", &P[i].x, &P[i].y);
}
memset(A, 0, sizeof(A));
double max_area = -1;
double min_area = (LL)INF * INF * 2.;
for(int i = 0; i < N; i ++) {
for(int j = i + 1; j < N; j ++) {
for(int k = j + 1; k < N; k ++) {
double cur_area = area(P[i].x, P[i].y, P[j].x, P[j].y, P[k].x, P[k].y);
if(cur_area <= eps) continue;
pair<double, double> tmp1 = getZx(i, j, k);
pair<double, double> tmp2 = getZx(A[0][0], A[0][1], A[0][2]);
pair<double, double> tmp3 = getZx(A[1][0], A[1][1], A[1][2]);
if(cur_area - max_area > eps ||
fabs(cur_area - max_area) <= eps && (tmp1.first - tmp2.first > eps ||
fabs(tmp1.first - tmp2.first) <= eps && tmp1.second - tmp2.second > eps)) {
max_area = cur_area;
A[0][0] = i, A[0][1] = j, A[0][2] = k;
}
if(min_area - cur_area > eps ||
fabs(min_area - cur_area) <= eps && (tmp3.first - tmp1.first > eps ||
fabs(tmp3.first - tmp1.first) <= eps && tmp3.second - tmp1.second > eps)) {
min_area = cur_area;
A[1][0] = i, A[1][1] = j, A[1][2] = k;
}
}
}
}
pair<double, double> a = getZx(A[0][0], A[0][1], A[0][2]);
pair<double, double> b = getZx(A[1][0], A[1][1], A[1][2]);
double ret = (a.second - b.second) * (a.second - b.second) + (a.first - b.first) * (a.first - b.first);
printf("%.2f\n", sqrt(ret) / (2. * U));
}
}
小Hi与花盆
题解
两种思维方式:
- 直接处理,也就是说用一个map或者set来存储每一次的操作,比如说我向
00000000
插入5
,变成了0000X000
也就是说把8
变成了4
和3
,如此用一个map存起来,如果当前有一个值等于K就输出结果即可 - 用转正为负的方法,我们开始是不断往空的盆子里放花,现在变成了不断从盆子里拿花,我们将处理数据离线处理,然后从
N-1
次操作往前处理,很明显0
会不断增多,这样就有点类似于并查集了,我们合并连在一起的0
,当这个合并的值等于K
的时候是不是就是答案,当然我们必须找到最接近开始的操作
代码(map,set)
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <unordered_map>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int MAXN = 1e5 + 5;
const int MAXM = 5e6 + 5;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
int N, K;
set<int> A;
int main() {
while(~scanf("%d%d", &N, &K)) {
A.clear();
A.insert(0);
A.insert(N + 1);
int t = -2, x;
for(int i = 0; i < N; i ++) {
scanf("%d", &x);
if(t != -2) continue;
set<int>::iterator it = A.upper_bound(x);
int r = *it --;
int l = *it;
if(K == x - l - 1 || K == r - x - 1) {
t = i;
}
A.insert(x);
}
printf("%d\n", t + 1);
}
return 0;
}
代码(并查集)
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <unordered_map>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int MAXN = 2e5 + 5;
const int MAXM = 5e6 + 5;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
int N, K;
int par[MAXN];
int cnt[MAXN];
int A[MAXN];
void init(){
for(int i = 0;i < MAXN;i ++) par[i] = i, cnt[i] = 0;
}
int _find(int x){
return x == par[x] ? x : par[x] = _find(par[x]);
}
int unit(int a, int b){
a = _find(a);
b = _find(b);
if(a == b) return cnt[a];
par[a] = b;
cnt[b] += cnt[a];
return cnt[b];
}
int main() {
while(~scanf("%d%d", &N, &K)) {
init();
for(int i = 0;i < N;i ++) scanf("%d", &A[i]);
int ret = -1;
int kt = 0;
for(int i = N - 1;i >= 0;i --){
cnt[A[i]] = 1;
int tmp = 1;
if(A[i] - 1 >= 1 && cnt[A[i] - 1]){
int t = cnt[_find(A[i] - 1)];
tmp = unit(A[i], A[i] - 1);
if(t == K) kt --;
}
if(A[i] + 1 <= N && cnt[A[i] + 1]){
int t = cnt[_find(A[i] + 1)];
tmp = unit(A[i], A[i] + 1);
if(t == K) kt --;
}
if(tmp == K) kt ++;
if(kt > 0) ret = i;
//if(kt != -1) ret = kt;
}
printf("%d\n", ret);
}
return 0;
}
小Hi与矩阵
题解
将菱形转换为正方形,经典的针对求解曼哈顿距离的方法
代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAXN = 2e2 + 5;
int S[20 + 5][MAXN << 1][MAXN << 1];
int A[MAXN << 1][MAXN << 1];
int N;
int sum(int v, int x0, int y0, int x1, int y1) {
x0 --;
y0 --;
if(x0 < 0) x0 = 0;
if(y0 < 0) y0 = 0;
if(x1 >= N * 2) x1 = N * 2;
if(y1 >= N * 2) y1 = N * 2;
return S[v][x1][y1] - S[v][x1][y0] - S[v][x0][y1] + S[v][x0][y0];
}
int main() {
int x;
while(~scanf("%d", &N)) {
memset(A, 0, sizeof(A));
memset(S, 0, sizeof(S));
for(int i = 1; i <= N; i ++) {
for(int j = 1; j <= N; j ++) {
scanf("%d", &x);
A[i + j - 1][N - i + j] = x;
}
}
int max_v = 0;
for(int i = 1; i <= 20; i ++) {
for(int j = 1; j <= N * 2; j ++) {
for(int k = 1; k <= N * 2; k ++) {
S[i][j][k] = S[i][j - 1][k] + S[i][j][k - 1] - S[i][j - 1][k - 1] + (i == A[j][k]);
}
}
}
int Q;
scanf("%d", &Q);
int y, k;
while(Q --) {
scanf("%d%d%d", &x, &y, &k);
int i = x + y - 1;
int j = N - x + y;
int ret = 0;
//printf("%d,%d,%d\n", i, j, k);
for(int f = 1; f <= 20; f ++) {
if(k % f == 0)ret += sum(f, i - k, j - k, i + k, j + k);
}
printf("%d\n", ret);
}
}
return 0;
}