codeforces round #230

codeforces_div230
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值