——暨GDKOI校队选拔赛
T1: 简单题
给出N个整数
X1,X2,X3,⋯,Xn
,将这
N
个数从小到大排序为
输入格式
输入文件的第1行为整数N(1≤N≤50000).
接下来的N行每行有一个整数,按顺序给出X1,X2,X3,…,Xn的值(|Xi|≤1000)
输出格式
给出整数T的值.
输入
3
1
3
2
输出
2
题解
居然有人理解成为偶数的项和与为奇数的项和的差。。。
程序
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 50500;
int a[N];
int main() {
int n, i, p = 0, q = 0;
scanf("%d", &n);
for (i = 0; i < n; i++) scanf("%d", &a[i]);
sort(a, a + n);
for (i = 0; i < n; i += 2) p += a[i];
for (i = 1; i < n; i += 2) q += a[i];
if (p < q) swap(p, q);
printf("%lld", p - q);
return 0;
}
T2: 电路稳定性
zzz有一个电路,电路上有n个元件。已知元件i损坏而断开的概率是Pi(i=1,2,…,n,0≤Pi≤1)。
请你帮zzz算出整个电路断路的概率。
元件的连接方式很简单,对电路的表示:
1. 一个元件是最小的电路,用A表示元件1,B表示元件2,如此类推。
2. k个电路组成的串联电路表示为:电路1,电路2,…,电路k。
k个电路组成的并联电路表示为:(电路1)(电路2)…(电路k)。
Input
第一行是一个整数n(1≤n≤26),表示一共有多少个元件;第二行是表示电路的字符串;最后是n行,每行是一个实数Pi(i=1,…n,0≤Pi≤1),表示该元件断路的概率。
Output
输出一个实数,表示整个电路断路的概率,精确到小数点后4位。
Sample Input
5(A,B)((C)(D),E)0.20.30.40.50.6
Sample Output
0.2992
题解
并联的概率是
串联的概率是
1−(1−P1)(1−P2)⋯(1−Pn)
,即1-串联不断路的概率。
至于字符串处理,递归也行,栈处理括号也行。
程序
#include <cstdio>
#include <cstring>
#include <list>
using namespace std;
const int N = 1000;
char c[N];
double stk[N], p[32];
list<double> s[N];
int main() {
int n, i, l, top = 0;
scanf("%d%s", &n, c);
stk[0] = 1.0;
for (i = 0; i < n; i++) scanf("%lf", p + i);
l = strlen(c);
for (i = 0; i < l; i++) {
if (c[i] == '(')
++top, stk[top] = 1.0;
else if (c[i] == ')') {
double tmp = 1.0 - stk[top];
for (list<double>::iterator it = s[top].begin();
it != s[top].end(); it ++)
tmp *= 1.0 - *it;
s[top].clear();
--top, stk[top] *= 1.0 - tmp;
} else if (c[i] == ',')
s[top].push_back(stk[top]), stk[top] = 1;
else
stk[top] *= p[c[i] - 'A'];
}
printf("%.4lf", stk[0]);
return 0;
}
T3
描述
Lordaeron市的我地图是一个n*n的矩阵,其中标号为1的表示商业区,标号为0的表示居民区。为了考察市内居民区与商业区的距离,并对此做出评估,市长Arthas希望你能够编写一个程序完成这一任务。
居民区i到商业区的距离指的是到距离它最近的商业区j的距离(
∣∣Xi−Xj∣∣+∣∣Yi−Yj∣∣
),而你将统计的是对于城市中的每一个区域
k
,以它为中心,所有满足
输入格式
输入文件的第1行为整数
T(1≤T≤30)
,表示输入数据的组数。
每组数据的第1行为
n,r(1≤r<n≤150)
,第2行起为一个
n⋅n
的矩阵。
输出格式
对每个输入数据,输出一个
n⋅n
的矩阵。
输出矩阵间有空行
输入样例
1
4 1
1 0 0 0
1 1 0 0
0 1 1 0
0 1 0 0
0 1 1 0
输出样例
1 4 9 8
2 5 10 9
2 4 7 7
2 3 4 4
题解
考试时样例多了最后一行。。。其实忽略它就行了。
而且没告诉输出数据间有空行。。。
首先如何快速求i距离最近的商业区的曼哈顿距离,发现实际上如果确定了曼哈顿距离,那么商业区所处的位置就围成了一个旋转了45°的正方形,显然我们可以二分这个距离,问题是使用前缀和判断有无商业区在旋转了45°的正方形不方便,我们可以将坐标系倒过来。
令
x′=x−y,y′=x+y
,自己画一下图就知道结果如何了。
于是用两次前缀和即可。复杂度
O(n2logn)
。
我的Region的写法比较坑。。
程序
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000;
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
struct Array {
int c[N][N];
int &get(int x, int y) { return c[x + 500][y + 500]; }
int *operator [](int x) { return c[x]; }
void clear() {
memset(c, 0, sizeof c);
}
};
struct Region {
Array c, s;
int &get(int x, int y) { return c.get(x, y); }
void process() {
int i, j;
for (i = 0; i < N; i++) s[i][0] = s[0][i] = 0;
for (i = 1; i < N; i++)
for (j = 1; j < N; j++)
s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + c[i][j];
}
int query(int x1, int y1, int x2, int y2) {
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
x1--; y1--;
return s.get(x2, y2) - s.get(x1, y2) - s.get(x2, y1) + s.get(x1, y1);
}
void init() {
c.clear(); s.clear();
}
} rg_rotated, rg_new;
int main() {
int t = read(), n, m, i, j, l, r, x, y, mid, ans;
while (t--) {
n = read(); m = read();
rg_rotated.init();
rg_new.init();
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
rg_rotated.get(i - j, i + j) = read();
rg_rotated.process();
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++) {
x = i - j; y = i + j;
l = 0; r = n;
while (l <= r) {
mid = l + r >> 1;
if (rg_rotated.query(x - mid, y - mid, x + mid, y + mid))
r = mid - 1, ans = mid;
else l = mid + 1;
}
rg_new.get(i, j) = ans;
}
rg_new.process();
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++)
printf("%d ", rg_new.query(i - m, j - m, i + m, j + m));
printf("\n");
}
printf("\n");
}
return 0;
}
T4: 烟花的寿命
(http://cojs.tk/cogs/problem/problem.php?pid=430)
然而oj上没有自定义校验器
描述
见过夜空中美丽的烟花吗,它们总是由一个块炸成多块,可能还会继续分裂成更小的块。然而,并不是每块都会继续发光。如果把一个烟花炸开的整个过程中的亮点记录下来,并给所有爆炸点标上号,你能算出它最长可能的存活时间吗?(指第一次爆炸到最后一次之间间隔的时问,假设任意两次相邻的爆炸时间间隔都是1秒)。
输入
(输入文件名fireworlk.in)
第1行一个数T,说明输入文件中共T组数据。每组的第l行是爆炸的总数N(1
输出
(输出文件名fireworlk.out)
对每组输入,输出若干行。第1行是最长的时间x(秒),接着输出x+1个数,每数占一行,给出最长时间是怎样达到的(从哪个点开始,经过哪些点)。如果存在多解,则任意输出一组解。
输入(firework.in)
2
3
1 2
1 3
4
1 2
2 4
3 2
输出(firework.out)
2
2
1
3
2
1
2
4
图为样例中第2组输出的示意图。
题解
神TM考官要我写自定义校验器。
发现就是求树的最长链。
一个dp x dfs搞定。
对于每个点,过其的链有两种情况,一种是从其父亲延续下来的,一种是过该节点,分别向两个孩子走的。
所以:dfs返回的是从该点到叶节点的最长距离。
func dfs(x, father, father_distance) {
child = []
for (v in adj[x] - father)
child += dfs(v, x, father_distance + 1)
ans = max{ans, child.min + father_distance + 1, child.min + child.second_min + 2}
return child.min
}
输出路径方案感觉是这道题最麻烦的地方?我的代码写的好丑。。
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
const int N = 1050, M = 2050, inf = 1000000000;
int h[N], v[M], p[M], cnt = 0, child[N], father[N];
void add(int x, int y) {
p[++cnt] = h[x]; v[cnt] = y; h[x] = cnt;
}
int ans, ans_rt, ans_fa, ans_c1, ans_c2;
int dp(int x, int fa, int fa_dis) {
int ma1 = -inf, ma1c = -1, ma2 = -inf, ma2c = -1, c;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa) {
c = dp(v[i], x, fa_dis + 1);
if (c > ma1) ma2c = ma1c, ma2 = ma1, ma1 = c, ma1c = v[i];
else if (c > ma2) ma2 = c, ma2c = v[i];
}
if (ma1 + fa_dis + 1 > ans) {
ans = ma1 + fa_dis + 1; ans_rt = x;
ans_fa = 1; ans_c1 = ma1c; ans_c2 = -1;
}
if (ma1 + ma2 + 2 > ans) {
ans = ma1 + ma2 + 2; ans_rt = x;
ans_fa = -1; ans_c1 = ma1c; ans_c2 = ma2c;
}
father[x] = fa;
child[x] = ma1c;
return ma1c == -1 ? 0 : (ma1 + 1);
}
vector<int> output;
int main() {
int t = read(), n, i, x, y, j;
while (t--) {
n = read(); cnt = ans = 0;
memset(h, 0, sizeof h);
for (i = 1; i < n; i++) {
x = read(); y = read();
add(x, y); add(y, x);
}
ans_fa = ans_c1 = ans_c2 = -1;
dp(1, 0, 0);
printf("%d\n", ans);
if (ans_fa != -1) {
output.clear();
for (j = ans_rt; j != 0; j = father[j])
output.push_back(j);
reverse(output.begin(), output.end());
for (j = 0; j < output.size(); j++)
printf("%d\n", output[j]);
}
if (ans_c2 != -1) {
output.clear();
for (j = ans_c2; j != -1; j = child[j])
output.push_back(j);
reverse(output.begin(), output.end());
for (j = 0; j < output.size(); j++)
printf("%d\n", output[j]);
printf("%d\n", ans_rt);
}
if (ans_c1 != -1) {
for (j = ans_c1; j != -1; j = child[j])
printf("%d\n", j);
}
}
return 0;
}
顺便自定义校验器(Cena 0.8.2)
#include <cstdio>
#include <string>
#include <fstream>
using namespace std;
const int N = 1050, M = 2050, inf = 1000000000;
int h[N], v[M], p[M], cnt = 0, ans;
void add(int x, int y) {
p[++cnt] = h[x]; v[cnt] = y; h[x] = cnt;
}
int main(int argc, char **argv) {
ifstream standard_input("firework.in");
ifstream standard_output(argv[2]);
ifstream player_output("firework.out");
ofstream score("score.log");
ofstream report("report.log");
int t, n, i, x, y, standard_time, player_time, fa = -1, s;
standard_input>>t;
for (int kase = 1; kase <= t; kase++) {
standard_input>>n; cnt = ans = 0;
memset(h, 0, sizeof h);
for (i = 1; i < n; i++) {
standard_input>>x>>y;
add(x, y); add(y, x);
}
standard_output>>standard_time;
for (i = 0; i <= standard_time; i++) standard_output>>x;
if (player_output.eof()) {
score<<"0";
report<<"数据组"<<kase<<"错误,选手文件意外结束"<<endl;
return 0;
}
player_output>>player_time;
if (player_time != standard_time) {
score<<"0";
report<<"数据组"<<kase<<"错误,标准输出时间:"<<standard_time<<",选手输出时间:"<<player_time<<endl;
return 0;
}
for (i = 0; i <= standard_time; i++) {
if (player_output.eof()) {
score<<"0";
report<<"数据组"<<kase<<"错误,选手文件意外结束"<<endl;
return 0;
}
player_output>>s;
if (s < 1 || s > n) {
score<<"0";
report<<"数据组"<<kase<<"错误,超出数据范围"<<endl;
return 0;
}
if (i > 0) {
bool flag = false;
for (int it = h[fa]; it; it = p[it])
if (v[it] == s) {
flag = true; break;
}
if (flag == false) {
score<<"0";
report<<"数据组"<<kase<<"错误,选手输出路径不存在"<<endl;
return 0;
}
}
fa = s;
}
}
score<<argv[1];
return 0;
}
这些题目都在谷歌找到了,然而百度都找不到。
想起2016冬令营开幕式讲的话了。。