codeforces_div230
A:
半径为n的圆,园内有一些整点,和它距离为1的点就连接起来,现在去掉一些点,使得圆内的点和圆外的点没有连接。
策略是选择圆内的点:
圆内选择肯定是靠近边界的点,如何选择?四个端点肯定是要选择的。(n, 0) (0, n) (0, -n), (-n, 0)四个点。
然后圆内的点,因为象限对称,只要考虑第一象限,如果横坐标为1,可以算出一个圆内的纵坐标y1,如果横坐标为2,也可以算出圆内的一个纵坐标y2。
那么肯定的是[[1,y1], [1, y2])的点都是要拿掉的。拿掉之后横坐标为1的点就没有和圆外相连接的了。那么用O(n)就可以推出有多少点,算前后纵坐标之差即可。
B:
经典汉诺塔问题,改成了费用问题。有几种移法
1:要原来一样,把n - 1移动到2,然后把最大的移动到3,现在变成了n - 1个盘子从2移动到3最小的费用。
2:把n - 1个盘子移动到3,然后把最大的移动到2,然后把n - 1个盘子移动到1,把最大的移动到3。
所以用dp[i][j][k][n],表示从i柱移动到j柱,辅助柱为k,移动n个盘子,状态转移为:
A:
半径为n的圆,园内有一些整点,和它距离为1的点就连接起来,现在去掉一些点,使得圆内的点和圆外的点没有连接。
策略是选择圆内的点:
圆内选择肯定是靠近边界的点,如何选择?四个端点肯定是要选择的。(n, 0) (0, n) (0, -n), (-n, 0)四个点。
然后圆内的点,因为象限对称,只要考虑第一象限,如果横坐标为1,可以算出一个圆内的纵坐标y1,如果横坐标为2,也可以算出圆内的一个纵坐标y2。
那么肯定的是[[1,y1], [1, y2])的点都是要拿掉的。拿掉之后横坐标为1的点就没有和圆外相连接的了。那么用O(n)就可以推出有多少点,算前后纵坐标之差即可。
如果纵坐标相同,还是要把前一个点删除掉,因为前面一个点的上面肯定是一个圆外的点。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
long long n;
long long ans;
int main() {
cin >> n;
if (n == 0) {
printf("1\n");
return 0;
}
if (n == 1) {
printf("4\n");
return 0;
}
int pre = sqrt(n * n - 1 + 1e-10);
ans = 0;
for (long long i = 2; i <= n; i++) {
int now_y = (int)sqrt(n * n - i * i + 1e-10);
if (now_y == pre) {
ans += 1;
}
else {
ans = ans + (long long)(pre - now_y);
}
pre = now_y;
}
cout << ans * 4 + 4 << endl;
return 0;
}
B:
经典汉诺塔问题,改成了费用问题。有几种移法
1:要原来一样,把n - 1移动到2,然后把最大的移动到3,现在变成了n - 1个盘子从2移动到3最小的费用。
2:把n - 1个盘子移动到3,然后把最大的移动到2,然后把n - 1个盘子移动到1,把最大的移动到3。
所以用dp[i][j][k][n],表示从i柱移动到j柱,辅助柱为k,移动n个盘子,状态转移为:
dp[i][j][k][n] = min(dp[i][k][j][n - 1] + t[i][j] + dp[k][j][i][n - 1], dp[i][j][k][n - 1] + t[i][k] + dp[j][i][k][n - 1] + t[k][j] + dp[i][j][k][n - 1]);
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAX_NUMBER = 50;
long long dp[4][4][4][MAX_NUMBER];
int vis[4][4][4][MAX_NUMBER];
long long money[4][4];
int n;
void dfs(int from, int to, int help, int number) {
if (vis[from][to][help][number] != -1) {
return ;
}
vis[from][to][help][number] = 1;
if (number == 1) {
vis[from][to][help][number] = 1;
long long temp_1 = money[from][to];
long long temp_2 = money[from][help] + money[help][to];
if (temp_1 < temp_2) {
dp[from][to][help][number] = temp_1;
}
else {
dp[from][to][help][number] = temp_2;
}
return ;
}
dfs(from, help, to, number - 1);
dfs(help, to, from, number - 1);
long long temp_1 = money[from][to] + dp[from][help][to][number - 1] + dp[help][to][from][number - 1];
dfs(from, to, help, number - 1);
dfs(to, from, help, number - 1);
long long temp_2 = money[from][help] + 2 * dp[from][to][help][number - 1] + dp[to][from][help][number - 1] + money[help][to];
if (temp_1 < temp_2) {
dp[from][to][help][number] = temp_1;
}
else {
dp[from][to][help][number] = temp_2;
}
}
int main() {
memset(vis, -1, sizeof(vis));
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
cin >> money[i][j];
}
}
cin >> n;
dfs(1, 3, 2, n);
long long ans = dp[1][3][2][n];
cout << ans << endl;
}