F. Girlfriend
题目大意: 给出 A,B,C,D,的坐标,和 K1,K2 求满足
| AP1 | >= K1 | BP1 | 和 | CP2 | >= K2 | DP2 | 条件下的 P1 所在的空间与 P2 所在的空间的相交体积
解题思路: 首先可以发现满足 | AP1 | >= K1 | BP1 | 的 P1 所在区域为空间中的球,下面给出推导;
这个方程在满足 t1 ^ 2 + t1 + t2 ^ 2 + t2 + t3 ^ 2 + t3大于 0 的时候才满足球的方程,题目数据应该会满足的吧
接下来题目要求的就是两个球冠的体积和了
下面的图,左边标注阴影的是球冠,右边是两球相交的截面图
是不是非常清楚呢
球冠的计算公式为 Pi * h * h * (r * 3 - h) / 3;
下面给出一重积分计算得出公式的过程
然后就是代码
求解的时候注意特判 不相交 和 包含 的关系
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, P> PP;
const int INF = 0x3f3f3f3f;
const int MAX_N = 1e6 + 10;
const int MOD = 1e9 + 7;
const double esp = 1e-9;
const double pi = 4.0 * atan(1.0);
int n;
double x[4], y[4], z[4], k[2];
double calc(double a1, double b1, double c1, double r1, double a2, double b2, double c2, double r2){
double dis = sqrt((a1 - a2) * (a1 - a2) + (b1 - b2) * (b1 - b2) + (c1 - c2) * (c1 - c2));
double res = 0;
if(dis >= r1 + r2){
res = 0;
}else if(dis + r1 <= r2){
res = (4.0 / 3.0) * pi * r1 * r1 * r1;
}else if(dis + r2 <= r1){
res = (4.0 / 3.0) * pi * r2 * r2 * r2;
}else{
double _cos = (r1 * r1 + dis * dis - r2 * r2) / (2.0 * r1 * dis);
double h = r1 * (1 - _cos);
res += pi / 3.0 * h * h * (3.0 * r1 - h);
_cos = (r2 * r2 + dis * dis - r1 * r1) / (2.0 * r2 * dis);
h = r2 * (1 - _cos);
res += pi / 3.0 * h * h * (3.0 * r2 - h);
}
return res;
}
void solve(){
double a1, b1, c1, r1, a2, b2, c2, r2;
double t, kk, d;
for(int i = 0; i < 4; i++){
scanf("%lf%lf%lf", &x[i], &y[i], &z[i]);
}
scanf("%lf%lf", &k[0], &k[1]);
t = (k[0] * k[0] - 1); kk = k[0] * k[0];
a1 = (kk * x[1] - x[0]) / t; b1 = (kk * y[1] - y[0]) / t; c1 = (kk * z[1] - z[0]) / t;
d = x[0] * x[0] + y[0] * y[0] + z[0] * z[0] - kk * (x[1] * x[1] + y[1] * y[1] + z[1] * z[1]);
r1 = sqrt(d / t + a1 * a1 + b1 * b1 + c1 * c1);
t = (k[1] * k[1] - 1); kk = k[1] * k[1];
a2 = (kk * x[3] - x[2]) / t; b2 = (kk * y[3] - y[2]) / t; c2 = (kk * z[3] - z[2]) / t;
d = x[2] * x[2] + y[2] * y[2] + z[2] * z[2] - kk * (x[3] * x[3] + y[3] * y[3] + z[3] * z[3]);
r2 = sqrt(d / t + a2 * a2 + b2 * b2 + c2 * c2);
printf("%.3f\n", calc(a1, b1, c1, r1, a2, b2, c2, r2));
}
int main(){
int TCASE = 1;
scanf("%d", &TCASE);
while(TCASE--) solve();
return 0;
}
I.Penguins
题目大意: 给出一个矩阵表示地图,’#’ 表示障碍物,左企鹅从左边的(20,20)出发,目的地是(1,20),右企鹅从右边的(20,1)出发,目的地是(1,1);求最小步数,并输出其中一种方案。
如果一次移动,某个企鹅到达障碍物或者越界的时候,那么它的移动被忽略。
样例:
input:
#................... .............##...#.
.................... .......#.....#.....#
.........#...#.#.... ...#....#...........
#........#.......... ...#..#.............
........#......#.... ..#.#......#.#.....#
......#.#..#.#....#. .......##.....##...#
....#...........#..# ....................
.##................. ...........#..#...#.
.....#.#........#.#. #.........#.#.......
.................... ..#....#..........#.
....#.#..........#.. .#.........#..#..#..
.........#.......#.. ..#.................
...#..#......#...#.. ......#.............
...........#...#.... ....................
..##..#.#....#..#... ..............#...#.
.#..#...#.#.....##.. .........#.#...#....
.#.........#........ ..............#.#...
..##.#........#...#. ##..................
....##.#............ .......#.....#......
..........##........ .#..#.#...........#.
output:
27
LULLUURRUUUUUUULUUUUURRUUUU
#..................A A............##...#.
...................A A......#.....#.....#
.........#...#.#...A A..#....#...........
#........#.........A A..#..#.............
........#......#.AAA AA#.#......#.#.....#
......#.#..#.#...A#. .A.....##.....##...#
....#...........#A.# .A..................
.##..............A.. .A.........#..#...#.
.....#.#........#A#. #A........#.#.......
.................AA. AA#....#..........#.
....#.#..........#A. A#.........#..#..#..
.........#.......#A. A.#.................
...#..#......#...#A. A.....#.............
...........#...#..A. A...................
..##..#.#....#..#.A. A.............#...#.
.#..#...#.#.....##A. A........#.#...#....
.#.........#....AAA. AAA...........#.#...
..##.#........#.A.#. ##A.................
....##.#........AAA. AAA....#.....#......
..........##......AA A#..#.#...........#.
解题思路: 跑一遍 BFS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, P> PP;
const int INF = 0x3f3f3f3f;
const int MAX_N = 1e6 + 10;
const int MOD = 1e9 + 7;
const double esp = 1e-9;
int n, k;
char sl[30][30], sr[30][30];
char res[1000];
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, -1, 1, 0};
int d[30][30][30][30];
PP pre[30][30][30][30];
void solve(){
for(int i = 0; i < 20; i++){
for(int j = 0; j < 20; j++){
for(int k = 0; k < 20; k++){
for(int l = 0; l < 20; l++){
d[i][j][k][l] = INF;
}
}
}
}
for(int i = 0; i < 20; i++){
scanf("%s", sl[i]);
scanf("%s", sr[i]);
}
d[19][19][19][0] = 0;
queue<PP> que;
que.push(PP(P(19, 19), P(19, 0)));
int xl, yl, xr, yr;
int txl, tyl, txr, tyr;
while(que.size()){
PP pp = que.front(); que.pop();
P pl = pp.first, pr = pp.second;
xl = pl.first, yl = pl.second, xr = pr.first, yr = pr.second;
for(int i = 0; i < 4; i++){
txl = xl + dx[i]; tyl = yl + dy[i];
txr = xr + dx[i]; tyr = yr - dy[i];
//左右企鹅都不会越界
if((txl >= 0 && txl <= 19 && tyl >= 0 && tyl <= 19) && (txr >= 0 && txr <= 19 && tyr >= 0 && tyr <= 19)){
//左右企鹅都走到障碍物,则没必要执行这次操作
if(sl[txl][tyl] == '#' && sr[txr][tyr] == '#') continue;
//左企鹅走到障碍物
if(sl[txl][tyl] == '#') txl = xl, tyl = yl;
//右企鹅走到障碍物
if(sr[txr][tyr] == '#') txr = xr, tyr = yr;
if(d[txl][tyl][txr][tyr] > d[xl][yl][xr][yr] + 1){
d[txl][tyl][txr][tyr] = d[xl][yl][xr][yr] + 1; que.push(PP(P(txl, tyl), P(txr, tyr)));
pre[txl][tyl][txr][tyr] = PP(P(xl, yl), P(xr, yr));
}
//右企鹅越界
}else if(txl >= 0 && txl <= 19 && tyl >= 0 && tyl <= 19 && sl[txl][tyl] != '#'){
txr = xr, tyr = yr;
if(d[txl][tyl][txr][tyr] > d[xl][yl][xr][yr] + 1){
d[txl][tyl][txr][tyr] = d[xl][yl][xr][yr] + 1; que.push(PP(P(txl, tyl), P(txr, tyr)));
pre[txl][tyl][txr][tyr] = PP(P(xl, yl), P(xr, yr));
}
//左企鹅越界
}else if(txr >= 0 && txr <= 19 && tyr >= 0 && tyr <= 19 && sr[txr][tyr] != '#'){
txl = xl, tyl = yl;
if(d[txl][tyl][txr][tyr] > d[xl][yl][xr][yr] + 1){
d[txl][tyl][txr][tyr] = d[xl][yl][xr][yr] + 1; que.push(PP(P(txl, tyl), P(txr, tyr)));
pre[txl][tyl][txr][tyr] = PP(P(xl, yl), P(xr, yr));
}
}
}
}
int t = 0;
xl = 0, yl = 19, xr = 0, yr = 0;
sl[0][19] = 'A'; sr[0][0] = 'A';
while(xl != 19 || yl != 19 || xr != 19 || yr != 0){
PP pp = pre[xl][yl][xr][yr];
P pl = pp.first, pr = pp.second;
txl = pl.first, tyl = pl.second, txr = pr.first, tyr = pr.second;
if(txl > xl || txr > xr) res[t++] = 'U';
else if(txl < xl || txr < xr) res[t++] = 'D';
else if(tyl < yl || tyr > yr) res[t++] = 'R';
else if(tyl > yl || tyr < yr) res[t++] = 'L';
xl = txl; yl = tyl; xr = txr; yr = tyr;
sl[txl][tyl] = 'A'; sr[txr][tyr] = 'A';
// cout << xl << ' ' << yl << ' ' << xr << ' ' << yr << '\n';
}
printf("%d\n", t);
for(int i = t - 1; i >= 0; i--) printf("%c", res[i]);
printf("\n");
for(int i = 0; i < 20; i++){
printf("%s ", sl[i]);
printf("%s\n", sr[i]);
}
}
int main(){
int TCASE = 1;
// scanf("%d", &TCASE);
while(TCASE--) solve();
return 0;
}
K.Stack
题目大意: 有一个数组 a,下标从 1 到 n,从 a[1] 遍历到 a[n],同时有一个栈,如果栈为空或者,a[i] 大于栈顶元素,则直接入栈,否则一直弹出栈顶元素,另一个数组 b 记录此时栈的元素个数。给出 n 和 k 个 b[i] 的值,求一种 a 的排列,不存在则输出 -1。
数据保证 a 的元素为一个排列,即 a[i] >= 1 && a[i] <= n; 任意 i, j, 如果 i,j不同,则 a[i] 和 a[j] 不同。
样例1:
输入
5 2
2 2
5 4
输出:
1 2 5 3 4
样例2:
输入
10 1
1 10
输出
-1
解题思路: 首先假设已知 b 数组的每个元素,且存在解,我们可以发现,b[i+1] 如果大于 b[i],则 b[i+1] = b[i] + 1; b[i+1] 如果小于等于 b[i],则 b[i+1] >= 1 && b[i+1] <= b[i];
通过已知 b[i] 的值,可以知道此时栈中需要有 b[i] - 1 个值小于 a[i],如果从后往前遍历,用一个栈来表示题目中的栈,当元素个数小于 b[i] ,则一直从小到大加入元素,否则栈顶作为 a[i],同时弹出栈顶元素,这样得出的数组总能满足条件。感觉是题目中栈的逆过程。严格证明我并不清楚
然后可以得知,如果然 b[i] 未知的由前一个一直的加 1 得来,最后存在差大于 1 得 b[i] 与 b[i+1] 得话,则无解,否则总有解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<double, double> P;
const int INF = 0x3f3f3f3f;
const int MAX_N = 1e6 + 10;
const int MOD = 1e9 + 7;
const double esp = 1e-9;
int n, k;
int b[MAX_N], res[MAX_N];
void solve(){
int p, x;
scanf("%d%d", &n, &k);
for(int i = 0; i < k; i++){
scanf("%d%d", &p, &x);
b[p] = x;
}
for(int i = 1; i <= n; i++){
if(b[i] == 0) b[i] = b[i - 1] + 1;
//无解结束
if(b[i] > b[i - 1] + 1){
printf("-1\n"); return;
}
}
stack<int> s;
int t = 1;
for(int i = n; i >= 1; i--){
//栈中元素少了
while(s.size() < b[i]) s.push(t++);
res[i] = s.top();
s.pop();
}
for(int i = 1; i < n; i++)
printf("%d ", res[i]);
printf("%d\n", res[n]);
}
int main(){
int TCASE = 1;
// scanf("%d", &TCASE);
while(TCASE--) solve();
return 0;
}