题目
http://118.190.20.162/home.page
T1 现值计算
思路
根据题意第 k k k年的 x x x元的当前价值为 x × ( 1 + i ) − k x\times (1+i)^{-k} x×(1+i)−k计算各个价值,最后求和。
代码
int main() {
int n; double i;
scanf("%d %lf", &n, &i);
i += 1;
double x = 0, y, z;
for (int k = 0; k <= n; k++) {
scanf("%lf", &y);
z = 1;
for (int j = 0; j < k; j++) {
z *= i;
}
x += (1.0 / z) * y;
}
printf("%f", x);
return 0;
}
T2 训练计划
思路
dp,设项目耗时为
c
(
i
)
c(i)
c(i),
科目
i
i
i的最早开始时间为:
a
(
i
)
=
a
(
p
i
)
+
c
(
p
i
)
a(i)=a(p_i)+c(p_i)
a(i)=a(pi)+c(pi)
其中
a
(
i
)
a(i)
a(i)初始化为1,最早可以从第1天开始训练。
科目
i
i
i的最晚开始时间为
b
(
i
)
=
m
i
n
p
u
=
i
(
b
(
u
)
−
c
(
u
)
)
b(i)=min_{p_{u}=i}(b(u)-c(u))
b(i)=minpu=i(b(u)−c(u))
其中
b
(
i
)
b(i)
b(i)初始化为
n
+
1
−
c
(
i
)
n+1-c(i)
n+1−c(i),这样保证最后一天完成所有训练。
若存在
b
(
i
)
<
1
b(i)<1
b(i)<1,则顿顿无法
n
n
n天内完成所有训练。
题目约束科目最多只有一个依赖,这样的图是森林,实际上,可以推广到DAG
图上。
代码
vector<int> q[105];
int a[105], b[105], c[105], g[105];
// 最早开始时间:所有先行项目完成的时间+1
// 最晚开始时间:所有后续项目所需的时间-1
void solve() {
int n, m, x;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> x;
if (x) {
g[i] = x, q[x].push_back(i);
} // 有x后续项目i(一个或多个)
a[i] = 1; // 所有项目最早可以在第1天开始
}
for (int i = 1; i <= m; i++) {
cin >> c[i];
b[i] = n - c[i] + 1;
}
for (int i = 1; i <= m; i++) {
if (!q[i].empty()) {
for (int k = 0; k < q[i].size(); k++) {
a[q[i][k]] = a[i] + c[i];
}
}
}
bool ok = 1;
for (int i = m; i >= 0; i--) {
if (g[i]) {
b[g[i]] = min(b[g[i]], b[i] - c[g[i]]);
if (b[g[i]] < 1) { ok = 0; break; }
}
}
for (int i = 1; i <= m; i++) cout << a[i] << " ";
if (ok) {
cout << '\n';
for (int i = 1; i <= m; i++) cout << b[i] << " ";
}
}
T3 JPEG 解码
思路
根据问题描述模拟:
- Z字形扫描,只有
8
×
8
8\times8
8×8的大小,很多方法都可以,观察到在没有矩阵的内部(而不是在边缘),扫描遵循
(
x
,
y
)
(x,y)
(x,y)均
+
1
,
−
1
+1,-1
+1,−1的规律,维护一个方向变量
dir
,每次移动 x , y x,y x,y同时加dir
。在矩形的边缘,我是假想它根据方向变量进行扫描,发现出界了,再修正,同时将dir
取反。
- 离散余弦变换,根据公式计算,4层的嵌套循环实现。
其他步骤略。
代码
const double pi = acos(-1);
int a[10][10], b[10][10];
double c[10][10];
void out() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
cout << b[i][j] << ' ';
} cout << '\n';
}
}
void solve() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
cin >> a[i][j];
}
}
int n, t;
cin >> n >> t;
int x, y, k; x = y = k = 0;
int dir = 1;
for (int i = 0; i < n; i++) {
cin >> b[x][y];
x -= dir; y += dir;
if (x < 0 || x > 7 || y < 0 || y > 7) {
if (x + y > 7 || (x == 8 && y == -1)) {
if (dir > 0) { x += 2, y--; }
else x--, y += 2;
dir = -dir;
} // (7,0)之后一步进入到另外一半
else {
// 出界,修正位置,更换方向
if (dir > 0) x += dir;
else y -= dir;
dir = -dir;
}
}
// printf("%d, %d\n", x, y);
}
if (!t) { out(); return; }
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
b[i][j] *= a[i][j];
}
}
if (t == 1) { out(); return; }
// 离散余弦逆变换
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
for (int u = 0; u < 8; u++) {
for (int v = 0; v < 8; v++) {
double au, av;
auto get = [&](int k) -> double {
if (!k) return sqrt(0.5);
else return 1;
};
au = get(u), av = get(v);
c[i][j] += au * av * b[u][v] * cos(pi / 8 * (0.5 + i) * u) * cos(pi / 8 * (0.5 + j) * v);
}
}
c[i][j] *= 0.25;
}
}
// 四舍五入
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
b[i][j] = (int)(c[i][j] + 128.5);
b[i][j] = max(0, b[i][j]);
b[i][j] = min(255, b[i][j]);
// cout << c[i][j] << ' ';
} // cout << '\n';
}
out();
}