AtCoder Beginner Contest 257

D - Jumping Takahashi 2

题目描述:

在二维平面上有n个蹦床,每个蹦床都有一个弹力值p,你自己有一个初始的弹跳能力S,从一个点蹦到另一个点的条件是 P i ∗ S > = ∣ x i − x j ∣ + ∣ y i − y j ∣ P_i * S >= |x_i-x_j|+|y_i - y_j| PiS>=xixj+yiyj

S最小为多少时,满足可以使得从任意一个点出发,能到达其他的任何一个点

思路:

根据上面那个式子,不难发现 S > = ⌈ ∣ x i − x j ∣ + ∣ y i − y j ∣ p i ⌉ S >= \lceil{\frac{|x_i-x_j|+|y_i-y_j|}{p_i}}\rceil S>=pixixj+yiyj

我们可以根据这个,作为两个点之间的距离,跑floyed维护出最短路上的最大权值,枚举每个点为起点,找出每个点到其他点的路径的最大值,取一个最小值即可

或者可以二分答案,然后dfs爆搜,但是这种方法我觉得复杂度太大没敢写

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
ll n, m, k, op, x;
struct ran{
    ll x, y;
    ll p;
}tr[MAX];
ll dis[205][205];
void work(){
    cin >> n;
    for(int i = 1; i <= n; ++i){
        cin >> tr[i].x >> tr[i].y >> tr[i].p;
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            dis[i][j] = (abs(tr[i].x - tr[j].x) + abs(tr[i].y - tr[j].y) + tr[i].p - 1) / tr[i].p;
        }
    }
    for(int k = 1; k <= n; ++k){
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= n; ++j){
                dis[i][j] = min(dis[i][j], max(dis[i][k] , dis[k][j]));
            }
        }
    }
    ll ans = 1e18;
    for(int i = 1; i <= n; ++i){
        ll cnt = 0;
        for(int j = 1; j <= n; ++j){
            cnt = max(cnt, dis[i][j]);
        }
        ans = min(ans, cnt);
    }
    cout << ans << endl;
}


int main(){
    io;
    work();
    return 0;
}


E - Addition and Multiplication 2

题目描述:

你现在有n元,你可以花c[i]元钱,使得当前获得的价值乘10 + i,最开始手里的价值为0,问最多能获得多大的价值

思路:

显然让长度尽可能长是最优的

满足长度最长的情况下,我们再考虑选择一些不会使得长度变小,且值i更大的,贪心就行

我们先确定结果是输出多少个数字,再去枚举每次输出哪个数字,枚举的时候从9枚举到1,判断剩余的钱减去当前的c[i]后会不会改变总的长度即可

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
int n, m, k, op, x;
int c[10];
void work(){
    cin >> n;
    for(int i = 1; i <= 9; ++i){
        cin >> c[i];
    }
    int minx = *min_element(c + 1, c + 10);
    k = n / minx;
    for(int i = 1; i <= k; ++i){
        for(int j = 9; j >= 1; --j){
            if(n - c[j] >= minx * (k - i)){
                n -= c[j];
                cout << j;
                break;
            }
        }
    }
}


int main(){
    io;
    work();
    return 0;
}

F - Teleporter Setting

题目描述:

n个点,m条边,每条边的权值都是1,有一些边的端点时0,则说明这条边是不固定的

现在需要输出n个数字,表示将所有不固定的边连接到i上去后,1到n的最短路

思路:

由于每次都是将所有不固定的边连接到一个相同的点上去,所以我们可以考虑建图的时候,把0作为特殊点,正常建图,然后我们跑两次bfs,分别求出以1为起点和以n为起点的时候的最短路,对于每次连接到i的情况,我们分两种情况,一种是不走那种特殊边,则答案就是1到n的最短路,另一种是走特殊边,这个时候我们可以把0看成i,分两种情况,一种是1到i,再从i到n,另一种情况是1到0,再从i到n,对这三种情况求个最小值就可以

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
int n, m, k, op, x, y;
vector<int>G[MAX];
int dis1[MAX];
int dis2[MAX];
void work(){
    cin >> n >> m;
    for(int i = 1; i <= m; ++i){
        cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    mem(dis1, inf);
    mem(dis2, inf);
    queue<int>q;
    q.push(1);
    dis1[1] = 0;
    while(!q.empty()){
        int u = q.front();q.pop();
        for(auto v : G[u]){
            if(dis1[v] != inf)continue;
            dis1[v] = dis1[u] + 1;
            q.push(v);
        }
    }
    q.push(n);
    dis2[n] = 0;
    while(!q.empty()){
        int u = q.front();q.pop();
        for(auto v : G[u]){
            if(dis2[v] != inf)continue;
            dis2[v] = dis2[u] + 1;
            q.push(v);
        }
    }
    for(int i = 1; i <= n; ++i){
        int ans = min(dis1[n], min(dis1[i] + dis2[0], dis1[0] + dis2[i]));
        if(ans == inf)cout << -1 << ' ';
        else cout << ans << ' ';
    }
    cout << endl;
}


int main(){
    io;
    work();
    return 0;
}


你可能感兴趣的:(Atcoder,算法,图论,最短路,贪心)